Last active
October 24, 2022 14:01
-
-
Save apankrat/612dde3d7f01c4713c9579b0a94d9547 to your computer and use it in GitHub Desktop.
Securing websocket connections on iOS with self-signed certificates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Accessing a website that uses a self-signed certificate using Mobile Safari | |
will throw a couple of warnings but will ultimately give an option for | |
temporarily accepting the certificate and then using the site as usual. | |
The certificate can also be installed as a system-wide "Security Profile" | |
on an iDevice; that is, manually added to the trusted certificate list. | |
This will eliminate the warnings and make a self-signed certificate look | |
and feel as a certificate issued by a trusted CA. | |
This is done exposing cert's file (.pem or .crt) via the website itself, | |
then visiting the link, e.g. https://website.ccc/cert.pem, and following | |
the prompts. | |
However self-signed certs do NOT work for websocket connections. This is | |
very poorly documented (if it all), but very easy to check. An attempt | |
to establish a wss:// connection towards a server that uses a self-signed | |
certificate will result in an empty error. | |
Manually installing the certificate doesn't help. | |
The workaround for this case is to use a certificate signed by a dummy CA. | |
That is, first make a self-signed CA certificate, install it on a device, | |
enable the "full trust" for it and then use to issue the actual server | |
certificate. The whole thing will still be completely homebaked, but now | |
the websocket connections will work. | |
To make a self-signed CA cert: | |
openssl req -new -x509 -days 3650 -config self.ca.conf -keyout ca.key -out ca.crt | |
whereby self.ca.conf contains: | |
[ req ] | |
default_bits = 2048 | |
encrypt_key = no | |
default_md = sha256 | |
prompt = no | |
utf8 = yes | |
distinguished_name = my_dn | |
x509_extensions = my_ext | |
[ my_dn ] | |
C=CH | |
CN=Honest Ivan & Co. | |
[ my_ext ] | |
keyUsage=critical, digitalSignature, keyEncipherment, keyCertSign | |
basicConstraints=critical,CA:TRUE | |
extendedKeyUsage=critical,serverAuth | |
subjectKeyIdentifier = hash | |
To make a CA-signed certificate: | |
openssl req -new -key example.key -out example.csr | |
openssl x509 -req -in example.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out example.crt -days 365 -sha256 -extfile ext.conf | |
whereby ext.conf contains: | |
keyUsage=critical, digitalSignature, keyEncipherment | |
basicConstraints=critical,CA:FALSE | |
extendedKeyUsage=critical,serverAuth | |
subjectKeyIdentifier = hash | |
Next, use example.key and example.crt to secure SSL version of the website. | |
Next, expose ca.crt on the website, open it from an iDevice, e.g. | |
https://website.ccc/ca.crt, and follow the prompts. | |
Finally, go into device Settings > General > About > Certificate Trust | |
and toggle "full trust" for the "Honest Ivan & Co." entry. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks so much for this!
For any readers: this doesn't work (any more?) on iOS without some changes. You must specify SANs in your ext.conf. Also one of the commands involves an input of "example.key", when you actually named it "ca.key" in the previous step.