SNI support



  • You mention eventually supporting SNI, it would be very useful for me as I use it on my server, and without it unfortutely DAVdroid can't connect.


  • developer

    Thank you. This is on the to-do list, but there's no easy solution (please see http://davdroid.bitfire.at/faq#c79 ). In the meanwhile, I can only recommend to mount your DAV service into the main HTTPS virtual host so that there's no need for SNI.



  • If you can't support SNI now, can you at least provide an option to disable ssl certificate checks?


  • developer

    I don't know if this would be wise because it would make SSL purposeless and you could use HTTP instead. Is it not an option for you to mount DAV on your main SSL virtual hosts?



  • This is not an option, for me. I would like my vhosts to be kept separated.

    If you use SSL it is mostly because you want to encrypt connexions.
    and if you chose to use this optin option (ignore cert issues), it is your responsibility.
    But best would be SNI support, of course...



  • Anyway you can bypass SNI problems by making your webserver present the SSL certificate that is awaited by the client app (davdroid).
    So, it roughly means moving your dav.example.com vhost at the beginning of your nginx/apache configuration.
    Then check with openssl and look if the good cert appears.

    openssl s_client -host dav.example.com -port 443
    


  • If you rely on SNI like I do, you have three basic options to make SSL work with DAVdroid:

    1. Make your DAV virtual host also listen on another port (e.g. both port 443 with SNI, and port 8443, where it always presents the DAV certificate).
    2. Make the DAV virtual host's certificate the default one (jeekajoo mentions how to do this with Apache; with Nginx you would do this by making the host that has default_server on its ssl listen directive present the correct certificate).
    3. Making DAV available on the current default virtual host, e.g., at both dav.example.org and www.example.org/dav/.

    I went with the first of these.

    As a side note, thank you so much for making DAVdroid. CardDAV support has been the one "missing piece" in my Android experience. I encourage everyone to donate.



  • Make the DAV virtual host's certificate the default one (jeekajoo mentions how to do this with Apache; with Nginx you would do this by making the host that has default_server on its ssl listen directive present the correct certificate).

    Actually what I mentioned also works with nginx. I tested it before writing my comment ;)



  • @jeekajoo: Sorry, I missed that. I guess if you haven't put default_server on any of the listen directives, it will use whichever is listed first.



  • I guess if you haven't put default_server on any of the listen directives

    that's correct :) by the way, thank you about the directive 'default_server.' I didn't know that one.



  • thank you about the directive 'default_server.' I didn't know this one.

    My pleasure. Also worth mentioning is that you can do this to not accept connections that have a host field that doesn't match any of yours:

    server {
       listen 80 default_server;
       listen 443 ssl default_server;
       ssl_certificate       /etc/ssl/certs/www.example.org.pem;
       ssl_certificate_key   /etc/ssl/private/example.org.key;
       server_name _;
       return 444;
    }
    

  • developer

    I have managed to get SNI basically working, but it will need some fine-tuning (proof of concept yet). The way is to do

    // HttpClient client
    ClientConnectionManager connectionManager = client.getConnectionManager();
    SchemeRegistry schemeRegistry = connectionManager.getSchemeRegistry();
    // register our own socket factory for HTTPS
    schemeRegistry.register(new Scheme("https", new SNISocketFactory(baseURL.getHost()), baseURL.getPort() == -1 ? 443 : baseURL.getPort()));
    

    then in the SNISocketFactory, which implements LayeredSocketFactory,

    // when it comes to connecting, use SSLCertificateSocketFactory because it's SNI-capable
    // insecure because we will do host name verification by ourselves (we have to enable SNI first!)
    sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getInsecure(0, null);
    SSLSocket s = (SSLSocket)sslSocketFactory.createSocket(hostName, port);
    // setHostname is only available for Android 4.2+
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
      sslSocketFactory.setHostname(s, hostName);
    // start SSL handshake, with SNI if set above
    s.startHandshake();
    // don't forget to verify the host name
    SSLSession session = s.getSession();
    if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostName, session))
                    throw new SSLPeerUnverifiedException("Cannot verify hostname: " + hostName);
    

    Only caveat: https://developer.android.com/reference/android/net/SSLCertificateSocketFactory.html#setHostname(java.net.Socket, java.lang.String) is only available from API level 17 (Android 4.2), so there's no SNI support for lower Android versions.

    I will merge this as soon as it's ready (which will be soon, hopefully).



  • Just for completeness: On Apache you would rename the conf file so that the site you wish to be the base site comes first. So, in /etc/httpd/conf.d I have:

    another_secure_site.conf
    owncloud.conf

    So I renamed owncloud.conf to aa_owncloud.conf so the listing now looks like

    aa_owncloud.conf
    another_secure_site.conf

    and now the correct certificate (after restarting apache) is delivered to non-SNI capable clients. Happy days. Perhaps I could put this info in a wiki somewhere. Is there one? I spent ages trying to get SSL to work with a self-signed cert before I read the entry in the FAQ about SNI support.


Log in to reply
 

Looks like your connection to Bitfire App Forums was lost, please wait while we try to reconnect.