]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added verification flag to disable wildcard checking
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 2 Apr 2014 08:51:46 +0000 (10:51 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 2 Apr 2014 08:51:46 +0000 (10:51 +0200)
This adds the verification flag GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS,
and gnutls_x509_crt_check_hostname2(), gnutls_openpgp_crt_check_hostname2().\v\18

13 files changed:
NEWS
lib/gnutls_cert.c
lib/gnutls_str.c
lib/gnutls_str.h
lib/gnutls_x509.c
lib/includes/gnutls/openpgp.h
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/openpgp/compat.c
lib/openpgp/gnutls_openpgp.h
lib/openpgp/pgp.c
lib/x509/rfc2818_hostname.c
tests/hostname-check.c

diff --git a/NEWS b/NEWS
index 2f558c13b6e5e61553023494ca0e3bb363d8a665..0b0ba4850b3133eddd510d5107b28f392e28f30c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -93,6 +93,7 @@ That option enables (when running on FIPS140-enabled system):
    than ECRYPT).
 
 ** API and ABI modifications:
+GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS: Added
 gnutls_privkey_generate: Added
 gnutls_pkcs11_crt_is_known: Added
 gnutls_fips140_mode_enabled: Added
@@ -109,6 +110,8 @@ gnutls_privkey_import_ecc_raw: Added
 gnutls_privkey_import_dsa_raw: Added
 gnutls_privkey_import_rsa_raw: Added
 gnutls_privkey_verify_params: Added
+gnutls_x509_crt_check_hostname2: Added
+gnutls_openpgp_crt_check_hostname2: Added
 gnutls_x509_name_constraints_init: Added
 gnutls_x509_name_constraints_deinit: Added
 gnutls_x509_crt_get_name_constraints: Added
index 9ad2aef03420fb28dd9380288df8d4c2cff34d3c..1b5f2034e8f97c1917c02fdf0af33338b66eb983 100644 (file)
@@ -575,6 +575,7 @@ _gnutls_openpgp_crt_verify_peers(gnutls_session_t session,
        cert_auth_info_t info;
        gnutls_certificate_credentials_t cred;
        int peer_certificate_list_size, ret;
+       unsigned int verify_flags;
 
        CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST);
 
@@ -594,6 +595,8 @@ _gnutls_openpgp_crt_verify_peers(gnutls_session_t session,
                return GNUTLS_E_NO_CERTIFICATE_FOUND;
        }
 
+       verify_flags = cred->verify_flags | session->internals.priorities.additional_verify_flags;
+
        /* generate a list of gnutls_certs based on the auth info
         * raw certs.
         */
@@ -609,7 +612,9 @@ _gnutls_openpgp_crt_verify_peers(gnutls_session_t session,
        ret =
            _gnutls_openpgp_verify_key(cred, hostname,
                                       &info->raw_certificate_list[0],
-                                      peer_certificate_list_size, status);
+                                      peer_certificate_list_size,
+                                      verify_flags,
+                                      status);
 
        if (ret < 0) {
                gnutls_assert();
@@ -630,6 +635,8 @@ _gnutls_openpgp_crt_verify_peers(gnutls_session_t session,
  * values or zero if the certificate is trusted. Note that value in @status
  * is set only when the return value of this function is success (i.e, failure 
  * to trust a certificate does not imply a negative return value).
+ * The default verification flags used by this function can be overriden
+ * using gnutls_certificate_set_verify_flags().
  *
  * If available the OCSP Certificate Status extension will be
  * utilized by this function.
@@ -685,6 +692,8 @@ gnutls_certificate_verify_peers2(gnutls_session_t session,
  * values or zero if the certificate is trusted. Note that value in @status
  * is set only when the return value of this function is success (i.e, failure 
  * to trust a certificate does not imply a negative return value).
+ * The default verification flags used by this function can be overriden
+ * using gnutls_certificate_set_verify_flags().
  *
  * If the @hostname provided is non-NULL then this function will compare
  * the hostname in the certificate against the given. The comparison will
index d94a54ac2331412ce02e7af01583cfe771cdbeea..54b6433fbee57a322599e190398cc0cc82cf4bf8 100644 (file)
@@ -604,7 +604,7 @@ hostname_compare_ascii(const char *certname,
  */
 int
 _gnutls_hostname_compare(const char *certname,
-                        size_t certnamesize, const char *hostname)
+                        size_t certnamesize, const char *hostname, unsigned vflags)
 {
        char *p;
        unsigned i;
@@ -614,7 +614,7 @@ _gnutls_hostname_compare(const char *certname,
                        return hostname_compare_raw(certname, certnamesize, hostname);
        }
 
-       if (*certname == '*') {
+       if (*certname == '*' && !(vflags & GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
                /* a wildcard certificate */
 
                /* ensure that we have at least two domain components after
@@ -628,7 +628,6 @@ _gnutls_hostname_compare(const char *certname,
                certnamesize--;
 
                while (1) {
-                       /* Use a recursive call to allow multiple wildcards */
                        if (hostname_compare_ascii(certname, certnamesize, hostname))
                                return 1;
 
index d497e8d1a3856b8c0d5aa1c42dd1eac09fe2200e..bc9d8bd66b8641656fbf74df3555674d8c692686 100644 (file)
@@ -114,7 +114,7 @@ int _gnutls_hex2bin(const char *hex_data, size_t hex_size,
                    uint8_t * bin_data, size_t * bin_size);
 
 int _gnutls_hostname_compare(const char *certname, size_t certnamesize,
-                            const char *hostname);
+                            const char *hostname, unsigned vflags);
 
 #define MAX_CN 256
 #define MAX_DN 1024
index 70d58a5d0cf43f9fce33dfea97b71688213f0ecd..2afcabf966c8446a670816d19567fd2f0e94c2dc 100644 (file)
@@ -300,8 +300,8 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session,
 
        if (hostname) {
                ret =
-                   gnutls_x509_crt_check_hostname(peer_certificate_list
-                                                  [0], hostname);
+                   gnutls_x509_crt_check_hostname2(peer_certificate_list
+                                                  [0], hostname, verify_flags);
                if (ret == 0)
                        *status |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID;
        }
index 1fee58fb497b11add38b51e69fd3fb537e607b07..11958b3764e4b9ebdea21f51402d4aaa1885743a 100644 (file)
@@ -110,6 +110,8 @@ int gnutls_openpgp_crt_get_key_id(gnutls_openpgp_crt_t key,
 
 int gnutls_openpgp_crt_check_hostname(gnutls_openpgp_crt_t key,
                                      const char *hostname);
+int gnutls_openpgp_crt_check_hostname2(gnutls_openpgp_crt_t key,
+                                     const char *hostname, unsigned int flags);
 
 int gnutls_openpgp_crt_get_revoked_status(gnutls_openpgp_crt_t key);
 
index f0d6c4e40e745176642fa33597f5945c62f17be8..25d662a16146686cdc48b1878634aa6927e9d929 100644 (file)
@@ -171,6 +171,8 @@ int gnutls_x509_crt_get_dn_by_oid(gnutls_x509_crt_t cert,
                                  size_t * buf_size);
 int gnutls_x509_crt_check_hostname(gnutls_x509_crt_t cert,
                                   const char *hostname);
+int gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
+                                   const char *hostname, unsigned int flags);
 
 int gnutls_x509_crt_get_signature_algorithm(gnutls_x509_crt_t cert);
 int gnutls_x509_crt_get_signature(gnutls_x509_crt_t cert,
@@ -790,6 +792,8 @@ int gnutls_pkcs7_delete_crl(gnutls_pkcs7_t pkcs7, int indx);
  *   this unless you understand the security implications.
  * @GNUTLS_VERIFY_DISABLE_CRL_CHECKS: Disable checking for validity
  *   using certificate revocation lists or the available OCSP data.
+ * @GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS: When including a hostname
+ *   check in the verification, do not consider any wildcards.
  *
  * Enumeration of different certificate verify flags. Additional
  * verification profiles can be set using GNUTLS_PROFILE_TO_VFLAGS()
@@ -807,6 +811,7 @@ typedef enum gnutls_certificate_verify_flags {
        GNUTLS_VERIFY_DISABLE_CRL_CHECKS = 1 << 9,
        GNUTLS_VERIFY_ALLOW_UNSORTED_CHAIN = 1 << 10,
        GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN = 1 << 11,
+       GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS = 1 << 12,
 } gnutls_certificate_verify_flags;
 
 /**
index 2b99150e0101c5a7d2ac365e66efd6ee33025f77..8834c093a7abfbd5322a615a963c1a787970be94 100644 (file)
@@ -1008,6 +1008,8 @@ GNUTLS_3_1_0 {
        gnutls_x509_key_purpose_get;
        gnutls_x509_ext_import_key_purposes;
        gnutls_x509_ext_export_key_purposes;
+       gnutls_x509_crt_check_hostname2;
+       gnutls_openpgp_crt_check_hostname2;
 } GNUTLS_3_0_0;
 
 GNUTLS_PRIVATE {
index 7c7bd698e499967e0ebc1114badfedd3251aed17..87cd5e96fb9aec855d8842ca2e30ba8673490484 100644 (file)
@@ -47,7 +47,9 @@ int
 _gnutls_openpgp_verify_key(const gnutls_certificate_credentials_t cred,
                           const char *hostname,
                           const gnutls_datum_t * cert_list,
-                          int cert_list_length, unsigned int *status)
+                          int cert_list_length,
+                          unsigned int verify_flags,
+                          unsigned int *status)
 {
        int ret = 0;
        gnutls_openpgp_crt_t key = NULL;
@@ -96,7 +98,7 @@ _gnutls_openpgp_verify_key(const gnutls_certificate_credentials_t cred,
                *status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
 
        if (hostname) {
-               ret = gnutls_openpgp_crt_check_hostname(key, hostname);
+               ret = gnutls_openpgp_crt_check_hostname2(key, hostname, verify_flags);
                if (ret == 0)
                        *status |= GNUTLS_CERT_UNEXPECTED_OWNER;
        }
index 8bd04dd735fe5f5e3a93107896c462d2f656b5bf..3227f98729e08e2ebdf5a73da22f0f9c14472df3 100644 (file)
@@ -59,7 +59,9 @@ _gnutls_openpgp_request_key(gnutls_session_t,
 int _gnutls_openpgp_verify_key(const gnutls_certificate_credentials_t,
                               const char *hostname,
                               const gnutls_datum_t * cert_list,
-                              int cert_list_length, unsigned int *status);
+                              int cert_list_length,
+                              unsigned int verify_flags,
+                              unsigned int *status);
 int _gnutls_openpgp_fingerprint(const gnutls_datum_t * cert,
                                unsigned char *fpr, size_t * fprlen);
 time_t _gnutls_openpgp_get_raw_key_creation_time(const gnutls_datum_t *
index c3bb9888224393cd0eaf0b61a568cc27f9309e4f..c3a53b4b9626d36d5d34722d0727d56e673cf8a3 100644 (file)
@@ -595,6 +595,28 @@ int gnutls_openpgp_crt_get_revoked_status(gnutls_openpgp_crt_t key)
 int
 gnutls_openpgp_crt_check_hostname(gnutls_openpgp_crt_t key,
                                  const char *hostname)
+{
+       return gnutls_openpgp_crt_check_hostname2(key, hostname, 0);
+}
+
+/**
+ * gnutls_openpgp_crt_check_hostname2:
+ * @key: should contain a #gnutls_openpgp_crt_t structure
+ * @hostname: A null terminated string that contains a DNS name
+ * @flags: gnutls_certificate_verify_flags
+ *
+ * This function will check if the given key's owner matches the
+ * given hostname. 
+ *
+ * Unless, the flag %GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS is specified,
+ * wildcards are only considered if the domain name consists of three
+ * components or more, and the wildcard starts at the leftmost position.
+ *
+ * Returns: non-zero for a successful match, and zero on failure.
+ **/
+int
+gnutls_openpgp_crt_check_hostname2(gnutls_openpgp_crt_t key,
+                                 const char *hostname, unsigned flags)
 {
        char dnsname[MAX_CN];
        size_t dnsnamesize;
@@ -614,7 +636,7 @@ gnutls_openpgp_crt_check_hostname(gnutls_openpgp_crt_t key,
                        dnsnamesize--;
 
                        if (_gnutls_hostname_compare
-                           (dnsname, dnsnamesize, hostname))
+                           (dnsname, dnsnamesize, hostname, flags))
                                return 1;
                }
        }
index 5412ccf8abc6337681b99542d295072ce430d5c3..2236052a9da259a8dc9cd75f06361451d4c883b3 100644 (file)
@@ -47,6 +47,33 @@ int
 gnutls_x509_crt_check_hostname(gnutls_x509_crt_t cert,
                               const char *hostname)
 {
+       return gnutls_x509_crt_check_hostname2(cert, hostname, 0);
+}
+
+/**
+ * gnutls_x509_crt_check_hostname:
+ * @cert: should contain an gnutls_x509_crt_t structure
+ * @hostname: A null terminated string that contains a DNS name
+ * @flags: gnutls_certificate_verify_flags
+ *
+ * This function will check if the given certificate's subject matches
+ * the given hostname.  This is a basic implementation of the matching
+ * described in RFC2818 (HTTPS), which takes into account wildcards,
+ * and the DNSName/IPAddress subject alternative name PKIX extension.
+ *
+ * The comparison may have false-negatives as it is done byte by byte in 
+ * non-ascii names.
+ *
+ * Unless, the flag %GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS is specified,
+ * wildcards are only considered if the domain name consists of three
+ * components or more, and the wildcard starts at the leftmost position.
+ *
+ * Returns: non-zero for a successful match, and zero on failure.
+ **/
+int
+gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
+                               const char *hostname, unsigned int flags)
+{
 
        char dnsname[MAX_CN];
        size_t dnsnamesize;
@@ -79,7 +106,7 @@ gnutls_x509_crt_check_hostname(gnutls_x509_crt_t cert,
                if (ret == GNUTLS_SAN_DNSNAME) {
                        found_dnsname = 1;
                        if (_gnutls_hostname_compare
-                           (dnsname, dnsnamesize, hostname)) {
+                           (dnsname, dnsnamesize, hostname, flags)) {
                                return 1;
                        }
                }
@@ -98,7 +125,7 @@ gnutls_x509_crt_check_hostname(gnutls_x509_crt_t cert,
                }
 
                if (_gnutls_hostname_compare
-                   (dnsname, dnsnamesize, hostname)) {
+                   (dnsname, dnsnamesize, hostname, flags)) {
                        return 1;
                }
        }
index a6b50879ce2b20d2e07247d80705594b0781c6b7..6a2f8d34fb38d4aff0eb57ce9c2f0d84e57dee5a 100644 (file)
@@ -772,6 +772,10 @@ void doit(void)
        if (!ret)
                fail("%d: Hostname incorrectly does not match (%d)\n", __LINE__, ret);
 
+       ret = gnutls_x509_crt_check_hostname2(x509, "www.example.org", GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
+       if (ret)
+               fail("%d: Hostname incorrectly matches (%d)\n", __LINE__, ret);
+
        ret = gnutls_x509_crt_check_hostname(x509, "foo.example.org");
        if (!ret)
                fail("%d: Hostname incorrectly does not match (%d)\n", __LINE__, ret);