Yet another self-signed cert question, but I’ve tried for several days to find the best/correct way to create a self-signed cert that will work in my development environment for the latest versions of Chrome, Android, and iOS.
The instructions I’ve found here and elsewhere are outdated for at least one of these platforms.
Here is the best I’ve found, but it only works with Chrome and Android.
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/C=US/ST=Oklahoma/L=Stillwater/O=My Company/OU=Engineering" -keyout ca.key -out ca.crt openssl genrsa -out "test.key" 2048 openssl req -new -key test.key -out test.csr -config openssl.cnf openssl x509 -req -days 3650 -in test.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extensions v3_req -extfile openssl.cnf -out test.crt openssl x509 -inform PEM -outform DER -in test.crt -out test.der.crt
Contents of openssl.cnf:
[req] default_bits = 2048 encrypt_key = no # Change to encrypt the private key using des3 or similar default_md = sha256 prompt = no utf8 = yes # Specify the DN here so we aren't prompted (along with prompt = no above). distinguished_name = req_distinguished_name # Extensions for SAN IP and SAN DNS req_extensions = v3_req # Be sure to update the subject to match your organization. [req_distinguished_name] C = US ST = Oklahoma L = Stillwater O = My Company OU = Engineering CN = test.com # Allow client and server auth. You may want to only allow server auth. # Link to SAN names. [v3_req] basicConstraints = CA:TRUE subjectKeyIdentifier = hash keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, serverAuth subjectAltName = @alt_names # Alternative names are specified as IP.# and DNS.# for IP addresses and # DNS accordingly. [alt_names] DNS.1 = test.com
After installing test.crt and test.key on my development server, this method works great for Chrome: just added test.crt to my Mac’s keychain and turned on “Always Trust” for it.
It also works great for Android: emailed test.der.crt to the device and tapped it to install. Most important: it showed up in the “USER” tab under Settings / Encryption & credentials / Trusted credentials. This is essential for using networkSecurityConfig in my Android app.
Unfortunately it didn’t work for iOS:
- I installed it in an Xcode simulator by dragging the certificates to it.
- I had to install both test.crt and ca.crt. If I just installed test.crt, it remained in “unverified” status, which makes sense since the ca.crt is the root certificate.
- It did not show up under Settings / About / Certificate Trust Settings which is required for me to turn it on.
- When my app tries to access my server with NSMutableURLRequest, it gets a “TIC SSL Trust Error” with 10 key-value pairs, including:
- NSErrorPeerCertificateChainKey=1 element, and NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “test.com” which could put your confidential information at risk.
Any idea how to change what I did so I can turn it on for iOS under “Certificate Trust Settings”?
Note 1: Since other answers to other questions about the -9813 error code suggested there may be a missing intermediate certificate, I added ca.crt to my Apache configuration for the SSLCaCertificateFile setting. It still worked fine for Chrome and Android, but had exactly the same error in iOS.
This answer has been updated (and simplified) to be compatible with iOS 13 and Android 8. Credit now goes to https://discussions.apple.com/thread/250666160 answer by user:fixitnowyes on October 6, 2019.
Just one openssl command works to create a self-signed certificate that works in Chrome, Android, and iOS:
openssl req -config openssl.cnf -new -x509 -days 825 -out ca.crt
This outputs both ca.crt and ca.key. Note that 825 days is the maximum duration allowed by iOS 13+, and it must be specified in the openssl command. The days setting in openssl.cnf does not do anything that I can tell.
Check information about the certificate with:
openssl x509 -in ca.crt -text -noout
[ req ] default_bits = 2048 default_keyfile = ca.key default_md = sha256 default_days = 825 encrypt_key = no distinguished_name = subject req_extensions = req_ext x509_extensions = x509_ext string_mask = utf8only prompt = no # The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description). # Its sort of a mashup. For example, RFC 4514 does not provide emailAddress. [ subject ] countryName = US stateOrProvinceName = Oklahoma localityName = Stillwater organizationName = My Company OU = Engineering # Use a friendly name here because it's presented to the user. The server's DNS # names are placed in Subject Alternate Names. Plus, DNS names here is deprecated # by both IETF and CA/Browser Forums. If you place a DNS name here, then you # must include the DNS name in the SAN too (otherwise, Chrome and others that # strictly follow the CA/Browser Baseline Requirements will fail). commonName = test.com emailAddress = [email protected] # Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ... [ x509_ext ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer # You only need digitalSignature below. *If* you don't allow # RSA Key transport (i.e., you use ephemeral cipher suites), then # omit keyEncipherment because that's key transport. basicConstraints = critical, CA:TRUE keyUsage = critical, digitalSignature, keyEncipherment, cRLSign, keyCertSign subjectAltName = DNS:test.com extendedKeyUsage = serverAuth # RFC 5280, Section 18.104.22.168 makes EKU optional # CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused # In either case, you probably only need serverAuth. extendedKeyUsage = TLS Web Server Authentication # Section req_ext is used when generating a certificate signing request. I.e., openssl req ... [ req_ext ] subjectKeyIdentifier = hash basicConstraints = CA:FALSE keyUsage = digitalSignature, keyEncipherment subjectAltName = DNS:test.com nsComment = "OpenSSL Generated Certificate" # RFC 5280, Section 22.214.171.124 makes EKU optional # CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused # In either case, you probably only need serverAuth. # extendedKeyUsage = serverAuth, clientAuth # [ alternate_names ] # DNS.1 = example.com # DNS.2 = www.example.com # DNS.3 = mail.example.com # DNS.4 = ftp.example.com # Add these if you need them. But usually you don't want them or # need them in production. You may need them for development. # DNS.5 = localhost # DNS.6 = localhost.localdomain # DNS.7 = 127.0.0.1 # IPv6 localhost # DNS.8 = ::1
After creating the certificates…
- Install ca.crt and ca.key in your server.
- Restart server.
Chrome / Safari installation:
- Add ca.crt to your Mac’s KeyChain Access in the System keychain (or PC equivalent).
- Set it to "Always Trust" (in Mac) so that it works in Chrome and Safari.
iOS device installation:
- Send ca.crt to your device and download it to Files
- Go to Files and open ca.crt
- Go to General / VPN & Device Management, find your cert (listed by domain), and install it
- Go to General / About / Certificate Trust Settings and turn on the certificate
iOS Xcode simulator installation:
- Drag ca.crt to the simulator. Note that there is no confirmation that anything happened.
- There should be no need to go to Settings / General / About / Certificate Trust Settings and enable it. It should be already enabled.
- Email ca.crt to your Gmail account, then log into Gmail in your
Android simulator and tap to install it.
- It should appear in the "USER" tab under Settings / Lock screen & security / Encryption & credentials / Trusted credentials.
Answered By – ScottyB