Android app certificate validation invalid #4277

Closed
opened 2026-02-20 03:03:15 -05:00 by deekerman · 15 comments
Owner

Originally created by @nodiaque on GitHub (Nov 12, 2024).

The bug

Hello,

When using a reverse proxy that have a certificate where the subject name doesn't match the domain but have alternate subject name that match, immich won't connect and throw an invalid certificat error

https://pastebin.com/imYAe9b1

As soon as I change the subject name for my wildcard domain (which is in the alternate subject), it work.

The OS that Immich Server is running on

Unraid

Version of Immich Server

1.12.0.1

Version of Immich Mobile App

1.20.0.1 build 166

Platform with the issue

  • Server
  • Web
  • Mobile

Your docker-compose.yml content

unraid, no docker compose

Your .env content

not using

Reproduction steps

  1. Setup a reverse proxy like Swag, Nginx
  2. Use a certificate file where the subject name doesn't match the domain (or isn't a wildcard to the immich subdomain) but do add the wildcard in the alternate subject
  3. Try to connect with the mobile app
    ...

Relevant log output

ApiException 400: TLS/SSL communication failed: GET /server/ping (Inner exception: HandshakeException: Handshake error in client (OS Error: 
	CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393)))

#0      _SecureFilterImpl._handshake (dart:io-patch/secure_socket_patch.dart:99)
#1      _SecureFilterImpl.handshake (dart:io-patch/secure_socket_patch.dart:143)
#2      _RawSecureSocket._secureHandshake (dart:io/secure_socket.dart:920)
#3      _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1049)
<asynchronous suspension>

Additional information

No response

Originally created by @nodiaque on GitHub (Nov 12, 2024). ### The bug Hello, When using a reverse proxy that have a certificate where the subject name doesn't match the domain but have alternate subject name that match, immich won't connect and throw an invalid certificat error https://pastebin.com/imYAe9b1 As soon as I change the subject name for my wildcard domain (which is in the alternate subject), it work. ### The OS that Immich Server is running on Unraid ### Version of Immich Server 1.12.0.1 ### Version of Immich Mobile App 1.20.0.1 build 166 ### Platform with the issue - [ ] Server - [ ] Web - [X] Mobile ### Your docker-compose.yml content ```YAML unraid, no docker compose ``` ### Your .env content ```Shell not using ``` ### Reproduction steps 1. Setup a reverse proxy like Swag, Nginx 2. Use a certificate file where the subject name doesn't match the domain (or isn't a wildcard to the immich subdomain) but do add the wildcard in the alternate subject 3. Try to connect with the mobile app ... ### Relevant log output ```shell ApiException 400: TLS/SSL communication failed: GET /server/ping (Inner exception: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393))) #0 _SecureFilterImpl._handshake (dart:io-patch/secure_socket_patch.dart:99) #1 _SecureFilterImpl.handshake (dart:io-patch/secure_socket_patch.dart:143) #2 _RawSecureSocket._secureHandshake (dart:io/secure_socket.dart:920) #3 _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1049) <asynchronous suspension> ``` ### Additional information _No response_
deekerman 2026-02-20 03:03:15 -05:00
Author
Owner

@bo0tzz commented on GitHub (Nov 12, 2024):

Can you clarify, is this a valid WebPKI certificate or something self signed?

@bo0tzz commented on GitHub (Nov 12, 2024): Can you clarify, is this a valid WebPKI certificate or something self signed?
Author
Owner

@nodiaque commented on GitHub (Nov 12, 2024):

Let's Encrypt certificate

@nodiaque commented on GitHub (Nov 12, 2024): Let's Encrypt certificate
Author
Owner

@nodiaque commented on GitHub (Nov 12, 2024):

Here's what I mean.

This is my server certificat. We can see here that the subject name (Objet, sorry it's in French) is something.duckdns.org. It is not a widcard. For privacy purpose, I blurred and renamed it a.duckdns.org. My immich server reside at immich.b.duckdns.org.

image

Here, you can see I have alternate subject set to DNS Name:

  • *.a.duckdns.org
  • *.b.duckdns.org
  • *.c.duckdns.org
  • b.duckdns.org
  • c.duckdns.org

image

@nodiaque commented on GitHub (Nov 12, 2024): Here's what I mean. This is my server certificat. We can see here that the subject name (Objet, sorry it's in French) is something.duckdns.org. It is not a widcard. For privacy purpose, I blurred and renamed it a.duckdns.org. My immich server reside at immich.b.duckdns.org. ![image](https://github.com/user-attachments/assets/e4804698-213a-4ee7-b8f7-ba4559ebb630) Here, you can see I have alternate subject set to DNS Name: - *.a.duckdns.org - *.b.duckdns.org - *.c.duckdns.org - b.duckdns.org - c.duckdns.org ![image](https://github.com/user-attachments/assets/f56fe9b8-9066-4c81-8ee4-d4135692416f)
Author
Owner

@mmomjian commented on GitHub (Nov 13, 2024):

I am not able to replicate this. My nginx serves a Lets Encrypt cert with a wildcard Subject Alternative Name and have had no issues on iOS or Android.

@mmomjian commented on GitHub (Nov 13, 2024): I am not able to replicate this. My nginx serves a Lets Encrypt cert with a wildcard Subject Alternative Name and have had no issues on iOS or Android.
Author
Owner

@nodiaque commented on GitHub (Nov 13, 2024):

Weirdly when I put back that certificat, it does the error back and it's made from the same software. Maybe when there's multiple alternative name? In my case, it was the third dns alternate name. Be sure that the subject doesn't match the domain nor subdomain.

@nodiaque commented on GitHub (Nov 13, 2024): Weirdly when I put back that certificat, it does the error back and it's made from the same software. Maybe when there's multiple alternative name? In my case, it was the third dns alternate name. Be sure that the subject doesn't match the domain nor subdomain.
Author
Owner

@mmomjian commented on GitHub (Nov 13, 2024):

My cert has like 20 alternate names , FWIW. And no, the subject doesn’t match

@mmomjian commented on GitHub (Nov 13, 2024): My cert has like 20 alternate names , FWIW. And no, the subject doesn’t match
Author
Owner

@nodiaque commented on GitHub (Nov 13, 2024):

I really don't know what to say. It's the only difference between this certificate and the one I'm using right now.

@nodiaque commented on GitHub (Nov 13, 2024): I really don't know what to say. It's the only difference between this certificate and the one I'm using right now.
Author
Owner

@squanbo commented on GitHub (Dec 10, 2024):

I encountered the same issue when using a reverse proxy. I am using a self-signed certificate and have enabled the 'Allow self-signed certificates' option in the settings. When opening a video on the Android client, the app crashes.

ApiException 400: TLS/SSL communication failed: GET /partners (Inner exception: HandshakeException: Handshake error in client (OS Error:
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393)))

#0 _SecureFilterImpl._handshake (dart:io-patch/secure_socket_patch.dart:99)
#1 _SecureFilterImpl.handshake (dart:io-patch/secure_socket_patch.dart:143)
#2 _RawSecureSocket._secureHandshake (dart:io/secure_socket.dart:920)
#3 _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1049)

@squanbo commented on GitHub (Dec 10, 2024): I encountered the same issue when using a reverse proxy. I am using a self-signed certificate and have enabled the 'Allow self-signed certificates' option in the settings. When opening a video on the Android client, the app crashes. ApiException 400: TLS/SSL communication failed: GET /partners (Inner exception: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393))) #0 _SecureFilterImpl._handshake (dart:io-patch/secure_socket_patch.dart:99) #1 _SecureFilterImpl.handshake (dart:io-patch/secure_socket_patch.dart:143) #2 _RawSecureSocket._secureHandshake (dart:io/secure_socket.dart:920) #3 _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1049) <asynchronous suspension>
Author
Owner

@mmomjian commented on GitHub (Dec 10, 2024):

I encountered the same issue when using a reverse proxy. I am using a self-signed certificate and have enabled the 'Allow self-signed certificates' option in the settings. When opening a video on the Android client, the app crashes.

ApiException 400: TLS/SSL communication failed: GET /partners (Inner exception: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393)))

#0 _SecureFilterImpl._handshake (dart:io-patch/secure_socket_patch.dart:99) #1 _SecureFilterImpl.handshake (dart:io-patch/secure_socket_patch.dart:143) #2 _RawSecureSocket._secureHandshake (dart:io/secure_socket.dart:920) #3 _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1049)

Your issue is not related. Self signed certs currently do not support video playback.

@mmomjian commented on GitHub (Dec 10, 2024): > I encountered the same issue when using a reverse proxy. I am using a self-signed certificate and have enabled the 'Allow self-signed certificates' option in the settings. When opening a video on the Android client, the app crashes. > > ApiException 400: TLS/SSL communication failed: GET /partners (Inner exception: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393))) > > #0 _SecureFilterImpl._handshake (dart:io-patch/secure_socket_patch.dart:99) #1 _SecureFilterImpl.handshake (dart:io-patch/secure_socket_patch.dart:143) #2 _RawSecureSocket._secureHandshake (dart:io/secure_socket.dart:920) #3 _RawSecureSocket._tryFilter (dart:io/secure_socket.dart:1049) Your issue is not related. Self signed certs currently do not support video playback.
Author
Owner

@mmomjian commented on GitHub (Dec 10, 2024):

@nodiaque please share your full domain name for us to be able to test on our end.

@mmomjian commented on GitHub (Dec 10, 2024): @nodiaque please share your full domain name for us to be able to test on our end.
Author
Owner

@nodiaque commented on GitHub (Dec 10, 2024):

is there a way to send private message in github? Cause I won't disclose my domain name publicy on the internet

@nodiaque commented on GitHub (Dec 10, 2024): is there a way to send private message in github? Cause I won't disclose my domain name publicy on the internet
Author
Owner

@mmomjian commented on GitHub (Dec 10, 2024):

You can join our discord and then ask to DM someone there

@mmomjian commented on GitHub (Dec 10, 2024): You can join our discord and then ask to DM someone there
Author
Owner

@bo0tzz commented on GitHub (Dec 10, 2024):

Is your reverse proxy sending the full certificate chain or only the leaf cert?

@bo0tzz commented on GitHub (Dec 10, 2024): Is your reverse proxy sending the full certificate chain or only the leaf cert?
Author
Owner

@mmomjian commented on GitHub (Dec 10, 2024):

Confirmed misconfigured reverse proxy.

@mmomjian commented on GitHub (Dec 10, 2024): Confirmed misconfigured reverse proxy.
Author
Owner

@nodiaque commented on GitHub (Dec 10, 2024):

problem solved. for those that might have this issue, in nginx ssl.conf, normally you have let's encrypt dealing with this without a problem but since I'm importing cert from somewhere else, I had to modify the configuration.

Default nginx/swag configuration

ssl_certificate /config/keys/cert.crt;
ssl_certificate_key /config/keys/cert.key;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /config/keys/cert.crt;

What's important to note here is:
cert.crt is actually a symlink to fullchain.pem
cert.key is a symlink to privkey.pem

My non working config was like that:

ssl_certificate /config/acme/####.duckdns.org.crt;
ssl_certificate_key /config/acme/####..duckdns.org.key;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /config/acme/###.duckdns.org.all.pem;

Weirdly enough, one would think that ssl_trusted_certificate would install the whole chain but no. So I changed the first line to
ssl_certificate /config/acme/###.duckdns.org.all.pem;
And voila, it's now resolving the chain properly.

For anyone else needing to check there ssl installation, this little tool work great. There's also an offline version if you don't have access from internet (ssl tools on the same page)

https://www.sslshopper.com/SSL-CHECKER.HTML

I should have followed my own advice, check my ssl installation and not blindly trust my docker ;)

@nodiaque commented on GitHub (Dec 10, 2024): problem solved. for those that might have this issue, in nginx ssl.conf, normally you have let's encrypt dealing with this without a problem but since I'm importing cert from somewhere else, I had to modify the configuration. Default nginx/swag configuration ``` ssl_certificate /config/keys/cert.crt; ssl_certificate_key /config/keys/cert.key; # verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /config/keys/cert.crt; ``` What's important to note here is: cert.crt is actually a symlink to fullchain.pem cert.key is a symlink to privkey.pem My non working config was like that: ``` ssl_certificate /config/acme/####.duckdns.org.crt; ssl_certificate_key /config/acme/####..duckdns.org.key; # verify chain of trust of OCSP response using Root CA and Intermediate certs ssl_trusted_certificate /config/acme/###.duckdns.org.all.pem; ``` Weirdly enough, one would think that ssl_trusted_certificate would install the whole chain but no. So I changed the first line to `ssl_certificate /config/acme/###.duckdns.org.all.pem;` And voila, it's now resolving the chain properly. For anyone else needing to check there ssl installation, this little tool work great. There's also an offline version if you don't have access from internet (ssl tools on the same page) https://www.sslshopper.com/SSL-CHECKER.HTML I should have followed my own advice, check my ssl installation and not blindly trust my docker ;)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/immich#4277
No description provided.