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 ---