Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Certificate is not working for TLS with self-signed .cer #16

Open
ccloli opened this issue Nov 24, 2019 · 28 comments
Open

Certificate is not working for TLS with self-signed .cer #16

ccloli opened this issue Nov 24, 2019 · 28 comments

Comments

@ccloli
Copy link

ccloli commented Nov 24, 2019

If the server side using a self-signed certificate, and the certificate using an invalid host name, the client cannot connect to the server, as the server side logs remote error: tls: bad certificate.

For example, I configured a server on 1.2.3.4, and self-signed a certificate and its host name is example.com (but I'm not holding it, so accessing the domain directly won't be my server). Then on the client side, I set the server to 1.2.3.4, and specified Hostname in plugin options as example.com, and paste the base64-encoded certificate content. Then I started the connection, but it's not working, server-side says remote error: tls: bad certificate.

The same configuration is working on Windows by importing the .cer file to trusted root certificate, and working on iOS by ignoring SSL error.

@nullstd
Copy link

nullstd commented Feb 11, 2020

I recently also met this problem, the root cause should lie in how this plugin handles certRaw generated from user inputs on Android, is there a way to show the data received by shadowsocks-android from this plugin?

@lixin9311
Copy link
Collaborator

lixin9311 commented Feb 11, 2020

Already fixed in the upstream shadowsocks/v2ray-plugin#128

@madeye Please make a new release?

@lixin9311
Copy link
Collaborator

The root cause was well-explained in the pull request.

Although I think it should be fixed on the caller side (e.g. Android app / WinGUI)...
It's difficult to set a multiline env/parameter right.
(see ProxyInstance.kt#L117, it stores the plugin config into JSON, which does not allow real line-breaks)
For the WinGUI, it's the UI design. (I would recommend you to pass the file instead of the content)

Maybe we should obsolete JSON, and start to use YAML.
Anyway, it the current fix for Android.

@Mygod
Copy link
Collaborator

Mygod commented Feb 11, 2020

JSON supports line break properly (have you tried \n). Personally I don't see why YAML is better than JSON. I would in fact argue for the opposite as JSON is typed.

@lixin9311
Copy link
Collaborator

FYI, https://www.gun.io/blog/multi-line-strings-in-json .
\n will not be treated as an escape sequence in JSON.
You can process those \n into line breaks after decoding the JSON. But that would not be standard behavior.

@nullstd
Copy link

nullstd commented Feb 12, 2020

I agree with @Mygod , it's OK to use \n in JSON string.

Also when I tested self-signed certificate using the build from this https://circleci.com/gh/shadowsocks/v2ray-plugin/20#artifacts, I tried both cert and certRaw(MUST use the original format including all the \n from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE-----, basically it just means you open the certificate file and copy all the content without any modifications, then paste it after certRaw=, it might look ugly but it works) parameters both on FreeBSD, they all work perfectly.

But when I tried the exactly same settings on Android, it never succeeds.

@lixin9311
Copy link
Collaborator

I agree with @Mygod , it's OK to use \n in JSON string.

Also when I tested self-signed certificate using the build from this https://circleci.com/gh/shadowsocks/v2ray-plugin/20#artifacts, I tried both cert and certRaw(MUST use the original format including all the \n from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE-----, basically it just means you open the certificate file and copy all the content without any modifications, then paste it after certRaw=, it might look ugly but it works) parameters both on FreeBSD, they all work perfectly.

But when I tried the exactly same settings on Android, it never succeeds.

I don't know which version of plugin and which implementation of ss are you testing.

Have you tried a JSON validator before use it?

@ccloli
Copy link
Author

ccloli commented Feb 12, 2020

\n will not be treated as an escape sequence in JSON.

@lixin9311 JSON comes from JavaScript, and in JavaScript, \n is the line break. And from JSON spec, it lists \n as linefeed escape character, so using \n in JSON is fine.

@lixin9311
Copy link
Collaborator

sry, my bad, I mean it should be:

{
  "var" : "first line
second line"
}

you mean:

{
  "var" : "first line\nsecond line"
}

@nullstd
Copy link

nullstd commented Feb 23, 2020

The root cause should be this:

After user inputs the PEM format certificate, the following code removes all the \n in it, which is wrong. To generate valid certificates from the PEM format certificate, all those \ns are necessary.

v2ray-plugin-android/app/src/main/java/com/github/shadowsocks/plugin/v2ray/ConfigFragment.kt#L66

        putWithDefault("certRaw", certRaw.text?.replace("\n", ""), "")

In addition, the following code also prevents from passing in the original PEM format certificate through plugin options.

shadowsocks-android/plugin/src/main/java/com/github/shadowsocks/plugin/PluginOptions.kt#L41

        check(options.all { !it.isISOControl() }) { "No control characters allowed." }

In order to fix this we need to come up with a solution to safely pass PEM format certificate. I have thought about using Base64 to encode/decode the certificate, what do you guys think?

@Mygod

@Mygod
Copy link
Collaborator

Mygod commented Feb 23, 2020

We cannot allow control characters. We could try removing the begin end lines and add it later.

@nullstd
Copy link

nullstd commented Feb 23, 2020

The problem is not only about the begin end lines, removing all the \n in raw certificate file violates the PEM certificate file format. Therefore if control characters are not accepted, maybe we'd better replace certRaw with cert64(Base64 encoded certificate, so that it's a single line without control characters), but this also needs changes from v2ray-plugin repository.

@Mygod
Copy link
Collaborator

Mygod commented Feb 23, 2020

Are you sure about that? I read RFC and I think it should be fine.

@nullstd
Copy link

nullstd commented Feb 23, 2020

Here is the code related to certRaw from v2ray-plugin:

https://github.com/shadowsocks/v2ray-plugin/blob/59b8f4fc46c7be399dad0620121a89efa656dc9c/main.go#L185-L191

		} else if *cert != "" || *certRaw != "" {
			certificate := tls.Certificate{Usage: tls.Certificate_AUTHORITY_VERIFY}
			certificate.Certificate, err = readCertificate()
			if err != nil {
				return nil, newError("failed to read cert").Base(err)
			}
			tlsConfig.Certificate = []*tls.Certificate{&certificate}

v2ray-plugin is written in Go, and Go Language API needs the original format without removing \ns, check the examples here:

https://golang.org/pkg/crypto/tls/#example_X509KeyPair

@ccloli
Copy link
Author

ccloli commented Feb 25, 2020

image

Removing \n in the base64 content should be fine, but \n after the first line (-----BEGIN CERTIFICATE-----) and before the last line (-----END CERTIFICATE-----) should be kept, or you'll get tls: failed to find any PEM data in certificate input.

Is it possible to allow control characters? Or just escape them like replacing \n as \\n and replacing them back from the plugin? Or in worst adding \n after the first line and before the last line automatically inside the plugin?

BTW does certRaw option also work in v2ray-plugin CLI? If so, how does the CLI handle the new lines?

@ccloli
Copy link
Author

ccloli commented Feb 25, 2020

Okay, as @lixin9311 says in shadowsocks/v2ray-plugin#128, the PR should fix the bug in CLI. Seems v1.3.1 has included upstream changes, however it's still not working, server-side still get remote error: tls: bad certificate.

Also v1.3.1 doesn't include config GUI, only has a single config input.

Screenshot_20200225-112325

@nullstd
Copy link

nullstd commented Feb 26, 2020

Mine does show the configuration dialogue properly, have you tried switching the system language to English? @ccloli

@nullstd
Copy link

nullstd commented Feb 27, 2020

I submitted #22 to fix this issue.

And another PR is also necessary to fix this:

shadowsocks/v2ray-plugin#190

Could you help review and merge that fix?

@Mygod

@ccloli
Copy link
Author

ccloli commented Feb 27, 2020

@jonkerfan I downloaded the debug apk file of your PR from Circle CI, seems it works fine (the config UI is also working).

On server-side it says accepted instead of bad certificate, the connection test from Shadowsocks is succeed. I also tested some other apps, looks like it doesn't have any problem, the proxy connection is working.

@nullstd
Copy link

nullstd commented Feb 28, 2020

What do you think ? @madeye

@elliott10
Copy link

Apply for a certificate from Let’s Encrypt, then v2ray-plugin from F-droid works fine.

Detail:
#14 (comment)

@ODtian
Copy link

ODtian commented Apr 22, 2020

@jonkerfan What version of android does plugin under? It doesn't work on android 10, seems ok when start but failed when I try to connect, the pc plugin works well.

@nullstd
Copy link

nullstd commented Apr 23, 2020

@ODtian
Mine is Android 9

@ODtian
Copy link

ODtian commented Apr 23, 2020

@jonkerfan Oh, it seems author 've already fix the problems which were mentioned in exist issues, in version 1.3.0, and I also try 1.3.1, but clearly none of them work on my device.
Is there any way to show the log of the plugin? so that I could find out what prevent me from connecting server.

@lu-ping
Copy link

lu-ping commented Nov 20, 2021

Same issue here on Mi 9 with Android 11 at Nov. 2021. get "remote error: tls: bad certificate" on server side with this plugin. windows & linux client works good. The discussion last for 2 years. do you guys have plan to fix this? I currently have to use websocket+http to get v2ray-plugin work on android.

BTW, why do we have to pass a CA? it could be optional, in my case I definitely trust my server and it's cert, as I signed it with a root CA created by me. I also installed it into android's trust CA storage. still not work. it could be phone's bug. so could we make supplying a CA from client optional? In GFW Trojan android client, install the CA certificate also not working. but trojan client can simply turn off verifing server cert with client CA functionality. ss android v2ray plugin could do same to get rid of this issue.

Sounds like v2ray plugin were trying to use root CA as a authentication way from server side, as the error is come up from server side! This is no point. because root CA normally is public. it is only used to verify the server is trustworthy in practice history of CA certificate.

@gitawong
Copy link

I encountered the same problem and found a workaround.
Of course, before this, you need to correctly configure the other settings of the Shadowsocks client for Android.

My server is self-registered using acme.sh. The public key file is generated as domain.cer. The content of domain.cer looks similar to the following:
-----BEGIN CERTIFICATE-----
public key
-----END CERTIFICATE-----
I copied the public key and paste it to config option "Certification for TLS verification" of v2ray plugin, then it works.

The issue only occurs when I hide my VPS IP using cloudflare and try to access the VPS directly by its IP address. So I guess this issue is caused by inconsistency between the IP address and the domain name.

@Abbode
Copy link

Abbode commented Jan 1, 2024

it's a mess, I'm having the same issue.
But I'm not a web developer, so I can't be so sure about the solution as you may be.

For me I tried self-signed and zerossl certificates, they both failed , and I had the same bad certificate error, whic is so annoying.

@anviar
Copy link

anviar commented Mar 2, 2024

workaround: copy content betwean -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- without newlines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants