gitblit-org / gitblit

pure java git solution
http://gitblit.com
Apache License 2.0
2.28k stars 670 forks source link

SSLHandshakeException on Federation #1391

Closed farzadrabiee closed 2 years ago

farzadrabiee commented 2 years ago

I installed 2 Gitblit, one of them is Origin (Windows 10) and another one is for federation backup (Docker). Version 1.9.1

I faced the error of using the HTTPS for origin.

federation.gitblit-federation.url = https://192.168.1.144:8443

2021-11-16 22:20:42 [ERROR] Failed to pull from federated gitblit (gitblit-federation @ https://192.168.1.144:8443) org.eclipse.jgit.api.errors.TransportException: https://192.168.1.144:8443/r/gitblit-federation.git: cannot open git-upload-pack at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:135) at org.eclipse.jgit.api.CloneCommand.fetch(CloneCommand.java:203) at org.eclipse.jgit.api.CloneCommand.call(CloneCommand.java:136) at com.gitblit.utils.JGitUtils.cloneRepository(JGitUtils.java:238) at com.gitblit.service.FederationPullService.pull(FederationPullService.java:213) at com.gitblit.service.FederationPullService.run(FederationPullService.java:96) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: org.eclipse.jgit.errors.TransportException: https://192.168.1.144:8443/r/gitblit-federation.git: cannot open git-upload-pack at org.eclipse.jgit.transport.TransportHttp.connect(TransportHttp.java:527) at org.eclipse.jgit.transport.TransportHttp.openFetch(TransportHttp.java:290) at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:136) at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:122) at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1201) at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:128) ... 12 more Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names present at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037) at sun.security.ssl.Handshaker.process_record(Handshaker.java:965) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1570) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498) at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:352) at org.eclipse.jgit.transport.http.JDKHttpConnection.getResponseCode(JDKHttpConnection.java:98) at org.eclipse.jgit.util.HttpSupport.response(HttpSupport.java:190) at org.eclipse.jgit.transport.TransportHttp.connect(TransportHttp.java:465) ... 17 more Caused by: java.security.cert.CertificateException: No subject alternative names present at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:145) at sun.security.util.HostnameChecker.match(HostnameChecker.java:94) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:462) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:442) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:209) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)

It works if I use the HTTP protocol, but need to use the HTTPS.

I knew the problem is related to the SSL Self-Signed, but can't solve the issue.

Can you please have a look at it?

flaix commented 2 years ago

This is caused because Java 8 from a certain version on enabled hostname verification of TLS certificates by default. What happens here is that the origin is accessed via a URL that does not match the CN in the origin's TLS certificate. Modern Java versions will check the name used in the URL against the ones in the certificate which will fail.

A way to fix this is to create a certificate for the origin that has the origin's hostname in it as CN. You address the origin via a IP address, but does it also have a hostname you could use? The Gitblit authority can help you create a server certificate with a CN other than the default localhost, but I am not sure that using a IP address will work. I believe that in order to use an IP address you may have to manually create a new certificate with a IP SubjectAlternativeName extension, instead of the DNS SAN extension.

flaix commented 2 years ago

Depending on your needs and how you use your Docker container, you could also have another option as a workaround. You are running this in a private network. If you require HTTPS but can accept that the certificate is not validated on the client, i.e. backup Gitblit, side, then (and only then) could you try to disable SSL verification for the Gitblit running in the docker container. If you have a fixed set of repositories, you could clone them once via HTTP and set the http.sslVerify option to false for each repo. Or you could set the option globally for the gitblit user in the container.

farzadrabiee commented 2 years ago

@flaix I just disabled http.sslVerify for the repository on the backup and it works.

Thanks

flaix commented 2 years ago

I'm happy if this works for you. Just remember that you can only do this in a network that you control fully, as you don't have certificate checks for the connection of this repository now.

farzadrabiee commented 2 years ago

Just a quick question.

I believe that in order to use an IP address you may have to manually create a new certificate with a IP SubjectAlternativeName extension, instead of the DNS SAN extension.

Do you have any document/resource about it? Thanks

flaix commented 2 years ago

I don't have anything from Gitblit's side that I know of. A quick Google search for SAN finds this page, which might be helpful: https://www.entrust.com/de/blog/2019/03/what-is-a-san-and-how-is-it-used/

Gitblit creates a CA certificate (self-signed, can issue other certificates) and a server certificate signed by that CA certificate. They are stored in the JKS keystore in the data folder. Gitblit comes with an application to issue new certificates, e.g. to create a new server certificate with other information in there specific to your server. It is started with the authority.cmd script. But AFAIK this application can not add a IP SAN extension. I haven't tried, though. So you would have to create a server certificate on your own, which you can do using the CA that Gitblit created. One way to make that easier (than using the keytool command on the command line) is to use the Keystore Explorer tool, which can open JKS keystores and can create certifiactes.

farzadrabiee commented 2 years ago

Thanks @flaix

farzadrabiee commented 2 years ago

Hi @flaix I just run the this command git config --global --bool --add http.sslVerify false to disable the verification of SSL for federation backup but it doesn't work.

I should go to each repository folder one by one and run git config http.SSL verify false.

You mentioned it's possible to set the option globally for the gitblit user in the container.

Could you please help me to set it globally? Thanks

flaix commented 2 years ago

I have not tried this myself, so this is theoretical knowledge, which might be wrong. The important part is that you execute that command as the user under which Gitblit runs. I don't know how your Docker container is set up, but by default the Gitblit Docker container has a gitblit user and Gitblit is started under this user account. Which means you would need to run this command in the container under this user. (For example using gosu or su-exec, if you are using the Alpine version.) You can check the .gitconfig file being created and edited by the git config --global command. It should exist in the gitblit user's home directory in the container, which is /opt/gitblit.

farzadrabiee commented 2 years ago

Seems the gosu or su-exec doesn't create the .gitconfig file in this path /opt/gitblit. So I created the file manually and add [http] sslVerify = false in it.

It works. Thanks @flaix

The size of repositories in Origin and Federation is different.

For example, one repository on Origin is 2.1GB but in the Federation is 1.7GB. Also for another repository, the Origin is 180MB and the Federation is 165MB.

Do you have any idea why are they different?

flaix commented 2 years ago

One possibility is that when fetching the repository the objects (files, trees, commits, etc.) are transferred and then stored in the packed format. The packed format is meant to save space. In normal operation objects are stored as normal files, which uses more disk space. You can check for that by comparing the objects folder of the git repositories between the origin and the federated one. While in the origin there are possibly many files and folders, in the federated one there is probably only one or more .pack files in the objects/pack folder.

farzadrabiee commented 2 years ago

Yes, correct. The object folder in Origin has contained many folders/files and the other side in Federation has just 4 files and the main one is .pack file

Thanks for your help @flaix

farzadrabiee commented 2 years ago

Hi @flaix,

I have a question to improve the security of the Federation.

The passphrase value on the gitblit.properties file creates a Token and then with this Token, we can use it as a Federation.

Is it possible to add another security option for the Federation?

For example, can I add the IP address of the Federation server on the Origin one?

Thanks