DAVx5 fails to send server-required SSL cert: "400 No required SSL certificate was sent" ?



  • I’ve a Radicale3 server serving up contacts/calendars.

    It sits behind an nginx reverse-proxy front end; auth to Radicale is provided by passthrough basic auth.

    With the following nginx config – with NO ssl client cert verification – DavX5 connects without issue:

    server {
    
    	listen 10.0.1.20:10000 ssl http2;
    	server_name front.example.com;
    	root /dev/null;
    	autoindex off;
    
    	ssl_verify_client off;
    	ssl_verify_depth 2;
    	ssl_client_certificate "/srv/ssl/myCA_CHAIN.crt";
    	ssl_certificate        "/srv/ssl/front.server.EC.crt";
    	ssl_certificate_key    "/srv/ssl/front.server.EC.key";
    
    	location / {
    		root /srv/nulldir;
    		allow 10.0.1.100;
    		deny all;
    		try_files $uri $uri/ =404;
    	}
    
    	location /dav/ {
    
    		proxy_pass https://radicale.example.com:20000/;
    		proxy_ssl_name radicale.example.com;
    		proxy_set_header  X-Script-Name /dav;
    
    		proxy_ssl_verify on;
    		proxy_ssl_verify_depth 2;
    
    		proxy_ssl_certificate         "/srv/ssl/radicale.client.EC.crt";
    		proxy_ssl_certificate_key     "/srv/ssl/radicale.client.EC.key";
    		proxy_ssl_trusted_certificate "/srv/ssl/myCA_CHAIN.crt";
    
    		auth_basic "DAV - Password Required";
    		auth_basic_user_file /srv/auth/radicale.auth;
    
    		include includes/reverse-proxy.inc;
    	}
    
    

    however,

    if I require ssl client verification,

    -	ssl_verify_client off;
    +	ssl_verify_client on;
    

    ensuring a valid cert on the phone, connection fails, apparently because DavX5 fails to send an SSL cert; debug logs follow.

    what additional config/settings are required for DavX5 to correctly serve-up the client-side cert for verification @ the server?

    --- BEGIN DEBUG INFO ---
    
    SYNCHRONIZATION INFO
    Account: Account {name=Card.001 (testuser@example.com Ug), type=at.bitfire.davdroid.address_book}
    Authority: com.android.contacts
    
    EXCEPTION
    at.bitfire.dav4jvm.exception.HttpException: HTTP 400 
    	at at.bitfire.dav4jvm.DavResource.checkStatus(DavResource.kt:6)
    	at at.bitfire.dav4jvm.DavResource.checkStatus(DavResource.kt:3)
    	at at.bitfire.dav4jvm.DavResource.processMultiStatus(DavResource.kt:1)
    	at at.bitfire.dav4jvm.DavResource.propfind(DavResource.kt:11)
    	at at.bitfire.davdroid.syncadapter.ContactsSyncManager$queryCapabilities$1.invoke(ContactsSyncManager.kt:3)
    	at at.bitfire.davdroid.syncadapter.ContactsSyncManager$queryCapabilities$1.invoke(ContactsSyncManager.kt:1)
    	at at.bitfire.davdroid.syncadapter.SyncManager.remoteExceptionContext(SyncManager.kt:1)
    	at at.bitfire.davdroid.syncadapter.SyncManager.remoteExceptionContext(SyncManager.kt:9)
    	at at.bitfire.davdroid.syncadapter.ContactsSyncManager.queryCapabilities(ContactsSyncManager.kt:3)
    	at at.bitfire.davdroid.syncadapter.SyncManager$performSync$1.invoke(SyncManager.kt:6)
    	at at.bitfire.davdroid.syncadapter.SyncManager$performSync$1.invoke(SyncManager.kt:1)
    	at at.bitfire.davdroid.syncadapter.SyncManager.unwrapExceptions(SyncManager.kt:1)
    	at at.bitfire.davdroid.syncadapter.SyncManager.performSync(SyncManager.kt:5)
    	at at.bitfire.davdroid.syncadapter.ContactsSyncAdapterService$ContactsSyncAdapter.sync(ContactsSyncAdapterService.kt:15)
    	at at.bitfire.davdroid.syncadapter.SyncAdapterService$SyncAdapter.onPerformSync(SyncAdapterService.kt:17)
    	at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:334)
    
    HTTP REQUEST
    Request{method=PROPFIND, url=https://front.example.com:10000/dav/testuser%40example.com/33333333-3333-3333-3333-333333333333/, headers=[Depth:0, Accept-Encoding:br,gzip]}
    <?xml version='1.0' encoding='UTF-8' ?><propfind xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav"><prop><CARD:supported-address-data /><supported-report-set /><n0:getctag xmlns:n0="http://calendarserver.org/ns/" /><sync-token /></prop></propfind>
    HTTP RESPONSEResponse{protocol=h2, code=400, message=, url=https://front.example.com:10000/dav/testuser%40example.com/33333333-3333-3333-3333-333333333333/}
    <html>
    <head><title>400 No required SSL certificate was sent</title></head>
    <body>
    <center><h1>400 Bad Request</h1></center>
    <center>No required SSL certificate was sent</center>
    <hr><center>nginx</center>
    </body>
    </html>
    
    REMOTE RESOURCE
    https://front.example.com:10000/dav/testuser%40example.com/33333333-3333-3333-3333-333333333333/
    
    SOFTWARE INFORMATION
    
    ┌────────────────────────────────┬─────────────┬───────────┬─────────────────────┬───────┐
    │ Package                        │ Version     │ Code      │ Installer           │ Notes │
    ├────────────────────────────────┼─────────────┼───────────┼─────────────────────┼───────┤
    │ at.bitfire.davdroid            │ 3.3.1-gplay │ 303010001 │ com.android.vending │       │
    │ org.dmfs.tasks                 │ 1.2.3       │ 77600     │ com.android.vending │       │
    │ com.android.providers.contacts │ 10          │ 29        │ —                   │       │
    │ com.android.providers.calendar │ 10          │ 29        │ —                   │       │
    │ com.android.contacts           │ 1.7.31      │ 10731     │ —                   │       │
    │ com.dw.contacts                │ 3.1.7.5     │ 3175      │ com.android.vending │       │
    │ org.lineageos.etar             │ 10          │ 29        │ —                   │       │
    │ com.aboutmycode.betteropenwith │ 1.4.11      │ 53        │ com.android.vending │       │
    │ com.appgenix.bizcal            │ 2.40.4      │ 240403    │ com.android.vending │       │
    └────────────────────────────────┴─────────────┴───────────┴─────────────────────┴───────┘
    
    SYSTEM INFORMATION
    
    Android version: 10 (lineage_star2lte-userdebug 10 QQ3A.200605.001 eng.rob.20200712.181146 test-keys)
    Device: samsung SM-G965F (star2lte)
    
    
    CONNECTVITY
    
     ☒ [ Transports: CELLULAR Capabilities: MMS SUPL IA INTERNET NOT_RESTRICTED TRUSTED NOT_VPN VALIDATED NOT_ROAMING FOREGROUND NOT_CONGESTED NOT_SUSPENDED LinkUpBandwidth>=15000Kbps LinkDnBandwidth>=30000Kbps Specifier: <1>]
    
    Data saver: disabled
    
    
    CONFIGURATION
    
    Power saving disabled: yes
    System-wide synchronization: automatically
    
    Notifications:
     - sync  isBlocked=false
      * syncProblems: importance=2
      * syncIoErrors: importance=1
      * syncWarnings: importance=2
     - cert4android: importance=2
     - general: importance=2
     - debug: importance=0
    
    Permissions:
     - READ_CONTACTS: granted
     - WRITE_CONTACTS: granted
     - READ_CALENDAR: granted
     - WRITE_CALENDAR: granted
     - READ_TASKS: granted
     - WRITE_TASKS: granted
     - ACCESS_COARSE_LOCATION: denied
    
    
    ACCOUNTS
    
     - Account: shared@example.com
    
    ┌──────────────────────────────────┬────────────┬──────────────────────┬───────────────┐
    │ Authority                        │ isSyncable │ getSyncAutomatically │ Sync interval │
    ├──────────────────────────────────┼────────────┼──────────────────────┼───────────────┤
    │ at.bitfire.davdroid.addressbooks │ 1          │ true                 │ 60 min        │
    │ com.android.calendar             │ 1          │ true                 │ 60 min        │
    │ com.android.contacts             │ 0          │ false                │ —             │
    │ org.dmfs.tasks                   │ 1          │ true                 │ 60 min        │
    └──────────────────────────────────┴────────────┴──────────────────────┴───────────────┘
    
    WiFi only: false
    Contact group method: CATEGORIES
    Time range (past days): null
    Default alarm (min before): null
    Manage calendar colors: true
    Use event colors: true
    
       * Address book: Card.Shared (shared@example.com eg)
       
       ┌────────────┬──────────────────────┬───────────────┐
       │ isSyncable │ getSyncAutomatically │ Sync interval │
       ├────────────┼──────────────────────┼───────────────┤
       │ 1          │ true                 │ 1440 min      │
       └────────────┴──────────────────────┴───────────────┘
       
          URL: https://front.example.com:10000/dav/shared%40example.com/22222222-2222-2222-2222-222222222222/
       Read-only: 0
    
     - Account: testuser@example.com
    
    ┌──────────────────────────────────┬────────────┬──────────────────────┬───────────────┐
    │ Authority                        │ isSyncable │ getSyncAutomatically │ Sync interval │
    ├──────────────────────────────────┼────────────┼──────────────────────┼───────────────┤
    │ at.bitfire.davdroid.addressbooks │ 1          │ true                 │ 60 min        │
    │ com.android.calendar             │ 1          │ true                 │ 60 min        │
    │ com.android.contacts             │ 0          │ false                │ —             │
    │ org.dmfs.tasks                   │ 1          │ true                 │ 60 min        │
    └──────────────────────────────────┴────────────┴──────────────────────┴───────────────┘
    
    WiFi only: false
    Contact group method: CATEGORIES
    Time range (past days): null
    Default alarm (min before): null
    Manage calendar colors: true
    Use event colors: true
    
       * Address book: Card.001 (testuser@example.com Ug)
       
       ┌────────────┬──────────────────────┬───────────────┐
       │ isSyncable │ getSyncAutomatically │ Sync interval │
       ├────────────┼──────────────────────┼───────────────┤
       │ 1          │ true                 │ —             │
       └────────────┴──────────────────────┴───────────────┘
       
          URL: https://front.example.com:10000/dav/testuser%40example.com/33333333-3333-3333-3333-333333333333/
       Read-only: 0
    
    
    DATABASE DUMP
    
    android_metadata
    
    ┌────────┐
    │ locale │
    ├────────┤
    │ en_US  │
    └────────┘
    
    service
    
    ┌────┬────────────────────────────┬─────────┬───────────────────────────────────────────────────────────────────────────────┐
    │ id │ accountName                │ type    │ principal                                                                     │
    ├────┼────────────────────────────┼─────────┼───────────────────────────────────────────────────────────────────────────────┤
    │ 7  │ shared@example.com         │ carddav │ https://front.example.com:10000/dav/shared%40example.com/                     │
    │ 8  │ shared@example.com         │ caldav  │ https://front.example.com:10000/dav/shared%40example.com/                     │
    │ 9  │ testuser@example.com       │ carddav │ https://front.example.com:10000/dav/testuser%40example.com/                   │
    │ 10 │ testuser@example.com       │ caldav  │ https://front.example.com:10000/dav/testuser%40example.com/                   │
    └────┴────────────────────────────┴─────────┴───────────────────────────────────────────────────────────────────────────────┘
    
    sqlite_sequence
    
    ┌────────────┬─────┐
    │ name       │ seq │
    ├────────────┼─────┤
    │ service    │ 10  │
    │ collection │ 10  │
    │ homeset    │ 10  │
    └────────────┴─────┘
    
    homeset
    
    ┌────┬───────────┬───────────────────────────────────────────────────────────────────────────────┬──────────┬─────────────┐
    │ id │ serviceId │ url                                                                           │ privBind │ displayName │
    ├────┼───────────┼───────────────────────────────────────────────────────────────────────────────┼──────────┼─────────────┤
    │ 7  │ 8         │ https://front.example.com:10000/dav/shared%40example.com/                     │ 1        │ —           │
    │ 8  │ 7         │ https://front.example.com:10000/dav/shared%40example.com/                     │ 1        │ —           │
    │ 9  │ 9         │ https://front.example.com:10000/dav/testuser%40example.com/                   │ 1        │ —           │
    │ 10 │ 10        │ https://front.example.com:10000/dav/testuser%40example.com/                   │ 1        │ —           │
    └────┴───────────┴───────────────────────────────────────────────────────────────────────────────┴──────────┴─────────────┘
    
    collection
    
    ┌────┬───────────┬──────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────┬────────────┬───────────────┬─────────────────┬─────────────────┬───────────┬──────────┬────────────────┬───────────────┬──────────────────┬────────┬──────┐
    │ id │ serviceId │ type         │ url                                                                                                                │ privWriteContent │ privUnbind │ forceReadOnly │ displayName     │ description     │ color     │ timezone │ supportsVEVENT │ supportsVTODO │ supportsVJOURNAL │ source │ sync │
    ├────┼───────────┼──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────┼────────────┼───────────────┼─────────────────┼─────────────────┼───────────┼──────────┼────────────────┼───────────────┼──────────────────┼────────┼──────┤
    │ 7  │ 8         │ CALENDAR     │ https://front.example.com:10000/dav/shared%40example.com/11111111-1111-1111-1111-111111111111/                     │ 1                │ 1          │ 0             │ Cal.Shared      │ Cal.Shared      │ -7021909  │ —        │ 1              │ 1             │ 1                │ —      │ 1    │
    │ 8  │ 7         │ ADDRESS_BOOK │ https://front.example.com:10000/dav/shared%40example.com/22222222-2222-2222-2222-222222222222/                     │ 1                │ 1          │ 0             │ Card.Shared     │ Card.Shared     │ —         │ —        │ —              │ —             │ —                │ —      │ 1    │
    │ 9  │ 9         │ ADDRESS_BOOK │ https://front.example.com:10000/dav/testuser%40example.com/33333333-3333-3333-3333-333333333333/                   │ 1                │ 1          │ 0             │ Card.001        │ Card.001        │ —         │ —        │ —              │ —             │ —                │ —      │ 1    │
    │ 10 │ 10        │ CALENDAR     │ https://front.example.com:10000/dav/testuser%40example.com/44444444-4444-4444-4444-444444444444/                   │ 1                │ 1          │ 0             │ Cal.001         │ Cal.001         │ -10782310 │ —        │ 1              │ 1             │ 1                │ —      │ 1    │
    └────┴───────────┴──────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────┴────────────┴───────────────┴─────────────────┴─────────────────┴───────────┴──────────┴────────────────┴───────────────┴──────────────────┴────────┴──────┘
    
    room_master_table
    
    ┌────┬──────────────────────────────────┐
    │ id │ identity_hash                    │
    ├────┼──────────────────────────────────┤
    │ 42 │ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa │
    └────┴──────────────────────────────────┘
    
    
    APP SETTINGS
    
    1. SharedPreferencesProvider canWrite=true
    
    ┌───────────────────────────┬───────────┐
    │ Setting                   │ Value     │
    ├───────────────────────────┼───────────┤
    │ distrust_system_certs     │ false     │
    │ hint_AutostartPermissions │ false     │
    │ log_to_file               │ true      │
    │ override_proxy            │ false     │
    │ override_proxy_host       │ localhost │
    │ override_proxy_port       │ 8118      │
    └───────────────────────────┴───────────┘
    
    2. DefaultsProvider canWrite=false
    
    ┌───────────────────────┬───────────┐
    │ Setting               │ Value     │
    ├───────────────────────┼───────────┤
    │ distrust_system_certs │ false     │
    │ override_proxy        │ false     │
    │ override_proxy_host   │ localhost │
    │ override_proxy_port   │ 8118      │
    └───────────────────────┴───────────┘
    
    --- END DEBUG INFO ---
    

  • developer

    Hi,

    Did you choose “Login with URL and client certificate” when creating the DAVx5 account?



  • I’d attempted that …

    However, in that config it no longer passes the password required for Radicale login.

    I need both: access control with cert to the Nginx front-end, and auth control with user:pass to the Radicale back-end.


  • developer

    @pgnd This is currently not possible with DAVx5, because there is no UI for that. See https://gitlab.com/bitfireAT/davx5-ose/-/wikis/Roadmap “login”



  • so it is either-or, not both at the moment.

    that feature will be useful – and necessary for several new/planned organization-wide implementations. here, anyway.

    is that feature tagged to a milestone? with any associated timeframe?


  • developer

    @pgnd said in DAVx5 fails to send server-required SSL cert: "400 No required SSL certificate was sent" ?:

    so it is either-or, not both at the moment.

    Yes.

    that feature will be useful – and necessary for several new/planned organization-wide implementations. here, anyway.

    I see. What is the use case? We have implemented client-side certificate for an organization, too. What is the user name/password needed for? Isn’t the client certificate used to identify the client?

    is that feature tagged to a milestone? with any associated timeframe?

    No, unfortunately not. There are so many other things at the moment.


  • developer

    There’s also already a merge request for that: https://gitlab.com/bitfireAT/davx5-ose/-/merge_requests/13 (as you can see, it’s only an UI thing; because the engine can already do Basic and client certificates)

    But there are some unresolved UI implications yet, and UI is always complicated.



  • What is the use case? We have implemented client-side certificate for an organization, too. What is the user name/password needed for? Isn’t the client certificate used to identify the client?

    the nginx front-end reverse-proxies many backend apps.

    the client cert provides access control for access to the front-end.

    auth to the backend apps is provided by their respective, individual auth mechanisms. typically username + strong-pass.

    that’ll eventually be additionally wrapped in an SSO portal that’ll add 2FA.



  • No, unfortunately not. There are so many other things at the moment.

    understood.

    as much as I personally like the davx5 client functionality/stability, it seems like this may not be the solution that fits for broader use here.


Log in to reply
 

Similar topics

  • 3
  • 10
  • 101