commit: r1679 - in neon/trunk: macros src

joe at manyfish.co.uk joe at manyfish.co.uk
Tue Aug 11 10:15:33 EDT 2009


Author: joe
Date: Tue Aug 11 07:15:33 2009
New Revision: 1679

Modified:
   neon/trunk/macros/neon.m4
   neon/trunk/src/ne_gnutls.c

Log:
* src/ne_string.c (ne_buffer_qappend): New function.

* src/ne_string.h (ne_buffer_qappend): New prototype.

* test/string-tests.c (qappend): New test case.


Modified: neon/trunk/macros/neon.m4
==============================================================================
--- neon/trunk/macros/neon.m4	(original)
+++ neon/trunk/macros/neon.m4	Tue Aug 11 07:15:33 2009
@@ -975,12 +975,6 @@
       ne_gnutls_ver=`$GNUTLS_CONFIG --version`
      ])
 
-   case $ne_gnutls_ver in
-   1.0.?|1.0.1?|1.0.20|1.0.21) 
-      AC_MSG_ERROR([GNU TLS version $ne_gnutls_ver is too old -- 1.0.22 or later required]) 
-      ;;
-   esac
-
    AC_CHECK_HEADER([gnutls/gnutls.h],,
       [AC_MSG_ERROR([could not find gnutls/gnutls.h in include path])])
 
@@ -989,10 +983,16 @@
    AC_DEFINE([HAVE_GNUTLS], 1, [Define if GnuTLS support is enabled])
 
    # Check for functions in later releases
-   NE_CHECK_FUNCS(gnutls_session_get_data2 gnutls_x509_dn_get_rdn_ava \ 
+   NE_CHECK_FUNCS([gnutls_session_get_data2 gnutls_x509_dn_get_rdn_ava \
                   gnutls_sign_callback_set \
-                  gnutls_certificate_get_x509_cas)
+                  gnutls_certificate_get_x509_cas \
+                  gnutls_certificate_verify_peers2])
 
+   # fail if gnutls_certificate_verify_peers2 is not found
+   if test x${ac_cv_func_gnutls_certificate_verify_peers2} != xyes; then
+       AC_MSG_ERROR([GnuTLS version predates gnutls_certificate_verify_peers2, newer version required])
+   fi
+                  
    # Check for iconv support if using the new RDN access functions:
    if test ${ac_cv_func_gnutls_x509_dn_get_rdn_ava}X${ac_cv_header_iconv_h} = yesXyes; then
       AC_CHECK_FUNCS(iconv)

Modified: neon/trunk/src/ne_gnutls.c
==============================================================================
--- neon/trunk/src/ne_gnutls.c	(original)
+++ neon/trunk/src/ne_gnutls.c	Tue Aug 11 07:15:33 2009
@@ -1,6 +1,6 @@
 /*
    neon SSL/TLS support using GNU TLS
-   Copyright (C) 2002-2008, Joe Orton <joe at manyfish.co.uk>
+   Copyright (C) 2002-2009, Joe Orton <joe at manyfish.co.uk>
    Copyright (C) 2004, Aleix Conchillo Flaque <aleix at member.fsf.org>
 
    This library is free software; you can redistribute it and/or
@@ -775,15 +775,60 @@
     return top;
 }
 
-/* Verifies an SSL server certificate. */
-static int check_certificate(ne_session *sess, gnutls_session sock,
-                             ne_ssl_certificate *chain)
+/* Map from GnuTLS verify failure mask *status to NE_SSL_* failure
+ * bitmask, which is returned.  *status is modified, removing all
+ * mapped bits. */
+static int map_verify_failures(unsigned int *status)
+{
+    static const struct {
+        gnutls_certificate_status_t from;
+        int to;
+    } map[] = {
+        { GNUTLS_CERT_REVOKED, NE_SSL_REVOKED },
+        { GNUTLS_CERT_NOT_ACTIVATED, NE_SSL_NOTYETVALID },
+        { GNUTLS_CERT_EXPIRED, NE_SSL_EXPIRED },
+        { GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND, NE_SSL_UNTRUSTED },
+        { GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_CA, NE_SSL_UNTRUSTED }
+    };
+    size_t n;
+    int ret = 0;
+
+    for (n = 0; n < sizeof(map)/sizeof(map[0]); n++) {
+        if ((*status & map[n].from) == map[n].from) {
+            *status &= ~map[n].from;
+            ret |= map[n].to;
+        }
+    }
+
+    return ret;
+}
+
+/* Return a malloc-allocated human-readable error string describing
+ * GnuTLS verification error bitmask 'status'; return value must be
+ * freed by the caller. */
+static char *verify_error_string(unsigned int status)
+{
+    ne_buffer *buf = ne_buffer_create();
+
+    /* sorry, i18n-ers */
+    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
+        ne_buffer_zappend(buf, _("signed using insecure algorithm"));
+    }
+    else {
+        ne_buffer_snprintf(buf, 64, _("unrecognized errors (%u)"),
+                           status);
+    }
+    
+    return ne_buffer_finish(buf);
+}
+
+/* Return NE_SSL_* failure bits after checking chain expiry. */
+static int check_chain_expiry(ne_ssl_certificate *chain)
 {
     time_t before, after, now = time(NULL);
-    int ret, failures = 0;
-    ne_uri server;
     ne_ssl_certificate *cert;
-
+    int failures = 0;
+    
     /* Check that all certs within the chain are inside their defined
      * validity period.  Note that the errors flagged for the server
      * cert are different from the generic error for issues higher up
@@ -796,7 +841,18 @@
             failures |= (cert == chain) ? NE_SSL_NOTYETVALID : NE_SSL_BADCHAIN;
         else if (now > after)
             failures |= (cert == chain) ? NE_SSL_EXPIRED : NE_SSL_BADCHAIN;
-    }        
+    }
+
+    return failures;
+}
+
+/* Verifies an SSL server certificate. */
+static int check_certificate(ne_session *sess, gnutls_session sock,
+                             ne_ssl_certificate *chain)
+{
+    int ret, failures;
+    ne_uri server;
+    unsigned int status;
 
     memset(&server, 0, sizeof server);
     ne_fill_server_uri(sess, &server);
@@ -807,15 +863,33 @@
         ne_set_error(sess, _("Server certificate was missing commonName "
                              "attribute in subject name"));
         return NE_ERROR;
-    } else if (ret > 0) {
+    } 
+    else if (ret > 0) {
         failures |= NE_SSL_IDMISMATCH;
     }
+    
+    failures |= check_chain_expiry(chain);
 
-    if (gnutls_certificate_verify_peers(sock)) {
-        failures |= NE_SSL_UNTRUSTED;
+    ret = gnutls_certificate_verify_peers2(sock, &status);
+    NE_DEBUG(NE_DBG_SSL, "ssl: Verify peers returned %d, status=%u\n", 
+             ret, status);
+    if (ret != GNUTLS_E_SUCCESS) {
+        ne_set_error(sess, _("Could not verify server certificate: %s"),
+                     gnutls_strerror(ret));
+        return NE_ERROR;
     }
 
-    NE_DEBUG(NE_DBG_SSL, "Failures = %d\n", failures);
+    failures |= map_verify_failures(&status);
+
+    NE_DEBUG(NE_DBG_SSL, "ssl: Verification failures = %d (status = %u).\n", 
+             failures, status);
+    
+    if (status && status != GNUTLS_CERT_INVALID) {
+        char *errstr = verify_error_string(status);
+        ne_set_error(sess, _("Certificate verification error: %s"), errstr);
+        ne_free(errstr);       
+        return NE_ERROR;
+    }
 
     if (failures == 0) {
         ret = NE_OK;



More information about the neon-commits mailing list