Here are the two certificates I picked randomly from the certificate transparency log. (I have tried some others to confirm the pattern.) One of them has empty Subject Common Name as well as Subject Alternative Name: critical and it does not work on iOS 9.3.5 Safari (does not mean causation though).
The certificate I'm getting for one of my domains name is similar to the latter (8476758885) in that it has empty Subject Common Name, X509v3 Subject Alternative Name is critical, and it does not work on iOS 9.3 Safari. It does work on the new devices though. I use certbot configured to talk to Buypass:
The closest I found is this advice to keep an eye on the order of -d arguments, but it does not apply because in the latter cert the CN is completely empty, it's not that the wrong domain had been picked.
Please help me figure this out or let me know if I need to provide more information. Thank you.
Certbot doesn't request a Subject Common Name in its Certificate Signing Request. Some CAs (like Let's Encrypt) always provide a certificate with one, but there's no requirement to do so beyond some potential compatibility hazards.
You can try making your own CSR and giving it to certbot with --csr rather than relying on Certbot to do it, or try patching Certbot to include a CN.
some CAs will not issue a cert with a Common Name, others will.
the Baseline Requirements (for all CAs) require the Common Name to be repeated in the SANs list
some clients and CAs will ignore the Common Name and order of SANs in the CSR, and will request/issue a Certificate with no Common Name and an alphabetically sorted SAN listing.
The only expected/required behavior across clients/servers is that a Common Name MUST be repeated in the SAN - as the Baseline Requirements state that. Everything else varies by client/server and will vary across versions so it is not guaranteed and likely to change.
It is and it isn't. It's a different issuer, but the same certbot and ACME. I was hoping with the level of expertise on this forum someone would still recognise the issue.
When going this route, I strongly advice to patch Certbot to include a CN. Not because I like hacking & patching (which I do), but because using --csr with Certbot REEEAAAALLLLLY isn't a very good idea. E.g., no automation and no storage into Certbots own "cert store"..
I'll try to put a simple patch into this thread this evening
Issuer: C = NO, O = Buypass AS-983163327, CN = Buypass Class 2 Root CA
Validity
Not Before: May 23 12:57:38 2017 GMT
Not After : May 23 12:57:38 2027 GMT
Subject: C = NO, O = Buypass AS-983163327, CN = Buypass Class 2 CA 5
Catch anything there?
iOS 9.3.5 was released in 2016. (WHY DO I KNOW THESE THINGS??? WHY?)
There's a 9.3.6 updated that came out on select hardware in 2019, but I don't think that updated the trust store.
Here is the trust store:
iOS 9.3.5 supports the Root CA in your chain, but not the intermediate.
Your intermediate is "Buypass Class 2 CA 5"; that version of iOS only supports:
Buypass Class 2 CA 1
Buypass Class 2 Root CA
Buypass Class 3 CA 1
Buypass Class 3 Root CA
You can work with your vendor to see if you can backport support somehow, otherwise you need to issue a Certificate via another CA that is compatible with your audience.
Edit: I have no idea why one is working, as the fullchains seem to be the same. One may be working due to short-circuit logic and caching, or an alternate chain being sent. Maybe the "critical" bit is affecting how iOS handles intermediates, as it's weird to me that BuyPass has intermediates in the Trust Store.
Output for www.pianomobil.com which does not work on iOS 9.3.5
CONNECTED(00000003)
depth=2 C = NO, O = Buypass AS-983163327, CN = Buypass Class 2 Root CA
verify return:1
depth=1 C = NO, O = Buypass AS-983163327, CN = Buypass Class 2 CA 5
verify return:1
depth=0
verify return:1
---
Certificate chain
0 s:
i:/C=NO/O=Buypass AS-983163327/CN=Buypass Class 2 CA 5
1 s:/C=NO/O=Buypass AS-983163327/CN=Buypass Class 2 CA 5
i:/C=NO/O=Buypass AS-983163327/CN=Buypass Class 2 Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGUzCCBDugAwIBAgILBLBkDX6dxo/fTVMwDQYJKoZIhvcNAQELBQAwSzELMAkG
A1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQD
DBRCdXlwYXNzIENsYXNzIDIgQ0EgNTAeFw0yMzAxMjEwNTU2MjBaFw0yMzA3MTky
MTU5MDBaMAAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHCP4B455b
tYXGzsKF9Kitr1O5rgfgKT+xkro55u3x8NX70hgfbidltlqdP1cGUm3jVhjHcuH/
S6fp4Ynluj6cVvBUM8+j0z6wQKp2jBlVmVjzsp9sW2slvedVuByTXsaYgsfEtjK8
zq43iIS/Ea2S8LlEw1IG9XPRWoiS6UBwWjZ/KFXEX2EHii/fsXeOKze9pB5aNzhO
TkwLSKi3gy8Khz9EtpUy1SCyCqyu6zKSPqefK/UQPFtPz8nkk8ewla3OzUm90ZGI
RKR90LmixLb8RtJkQGjyHXbtOqQ/M0gu0CQZxjJMsSBVtJ17OkEZHsKPXfIqGcMJ
PrgYetzY5gMzAgMBAAGjggKBMIICfTAJBgNVHRMEAjAAMB8GA1UdIwQYMBaAFCdS
pG8tKqtAk5Ds1mnL/nxhO3xCMB0GA1UdDgQWBBQM1+/nQmAvcpNa25Pl2xH3xEWu
4zAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MB8GA1UdIAQYMBYwCgYIYIRCARoBAgcwCAYGZ4EMAQIBMDoGA1UdHwQzMDEwL6At
oCuGKWh0dHA6Ly9jcmwuYnV5cGFzcy5uby9jcmwvQlBDbGFzczJDQTUuY3JsMDAG
A1UdEQEB/wQmMCSCDnBpYW5vbW9iaWwuY29tghJ3d3cucGlhbm9tb2JpbC5jb20w
agYIKwYBBQUHAQEEXjBcMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5idXlwYXNz
LmNvbTA1BggrBgEFBQcwAoYpaHR0cDovL2NydC5idXlwYXNzLm5vL2NydC9CUENs
YXNzMkNBNS5jZXIwggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdwDoPtDaPvUGNTLn
Vyi8iWvJA9PL0RFr7Otp4Xd9bQa9bgAAAYXS5js+AAAEAwBIMEYCIQDg+ruyTHYM
gybgUUjvFhRecVSkoHCJk7OHfNWucTP6+QIhAK7qDxP3EdBgdqJ2cHq1sCIqZ2zx
B8MO6z/0JWhS6Av2AHUAejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61IA
AAGF0uY7RgAABAMARjBEAiAMiLypp8MfiUZrRMdpWUYY7lwck6iGi4eAOzvOWP/g
lgIgP1JGr4fPO8QMjd5xDYZ0FSr1GTYqSBwEjxfpNmCTAxQwDQYJKoZIhvcNAQEL
BQADggIBAEF1Fzh/8nEmC7oR7EvZOo6HoVx+cKZAC8W9cmFrlu+EWyASGVu+UzCM
SdR7fxJL6XVN7udxhxlRr5NxU+rt4aqPuEITeLGeoqBvk/S388n4PEMWJrbZc+9T
HtMzuVB3I1Hm+gwB/YXgr76cDvmf+pyb0Q5q4v5HrcDCxwgVWSyOB+RnJ9cWcbJo
Zimic1tgWJnsIN/gmdB3WWTsj5ltqHs6BL1jBtiBSVEbRtq67vEoonbQX7TaRL8d
fOw6KwkK1fg5Cz7b7hIm7xW8TaT8LwSHoTybjmRtb2l1t/QQOn744YN/4bBPLFxc
Y5fP1ewt9CuRsxXaH3F+Xi6bjf5EfYPfFEgMjenbRd7PHGtEL6KZKg9tVxnV2wki
Wmek7j+fqcxoi4tG5VzgpLJ1J97D6RY6oN41JhBcqaGCLWkJ4eWSd4tD9ICteIW3
8JjXLD9YXOaRaDIa7x8E/pleuPsS8g03eDFRuLlYYF46frDVMZj3EpV031HyjCyb
a3PkLXQjdACRil2CRMzHhSPf7UHjr/CyQbe3EUZAxh144jFr8E7a8Aei/X0RokYQ
Htwo2o9cBjlIQt0BcCv+OwiCwNOHX/npQnh9JkR0zpCUQR2GV0wPTIOTjfOVitUe
FQxr0+JRq4y8VnCgdYQXPqJohlWBwvxV0TTrhR/93NmNYbFMdWdy
-----END CERTIFICATE-----
subject=
issuer=/C=NO/O=Buypass AS-983163327/CN=Buypass Class 2 CA 5
---
No client certificate CA names sent
Peer signing digest: SHA256
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 3699 bytes and written 428 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 0DDA6471EBE717166F76095BE1280FBA933ED348D5C3D984282C53DC7C51F9A5
Session-ID-ctx:
Master-Key: BE089849280111B3FFB7860B5454E52E88563EE391537F33F493C36AD72329427A3AC2CE4A1CC57AADC1BC402739CDC7
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1674497686
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
^C
From what I'm seeing – unless I ran the command wrong or am looking in the wrong place –
both domains have identical Certificate chain entries
both use Buypass Class 2 CA 5 as intermediary, which indeed is valid Not BeforeMay 23 12:57:38 2017 GMT (I couldn't figure out which command you used to get this output in command line, so I had to look up the cert details in my browser, the value I got is 23/05/2017 14:57:38 UTC+2, so same thing.)
Only obvious difference I'm seeing in the chains is the one that works on iOS 9.3.5 has the Subject CN.
Moreover, according to how my browser renders the Certificate Hierarchy, the Buypass Class 2 CA 5 is listed under Buypass Class 2 Root CA which is valid between 2010 and 2040.
I haven't maintained any iOS apps in a while, so my best advice right now is to track down some iOS people or talk to BuyPass and see if this may the cause:
Until LetsEncrypt faced the DST Root X3 Expiration, there were very little commonalities regarding what OpenSSL and various libraries did with Certificates and Certificate Chains. There still is a wide amount of variation and every browser/library handles things differently, but even as short as 3 years ago the industry was completely different.
The major behavior that current systems coalesced around, is that Certificate Chains are largely meaningless by default. Five years ago, a Certificate Chain may - or may not - have meant something. Today, the default standard is to pretty much ignore the chain and just focus on the trusted key pairings – as long as a client can build it's own path up to a Trusted Root, they really don't care what the server presents (expired intermediates, incorrect intermediates, etc). This is often called "short circuit logic" or "alternative pathbuilding".
The presence of BuyPass intermediates in the iOS, alongside their roots, in the iOS trust store makes me think there is some iOS specific behavior that required that. It is very rare to see intermediates in a trust store. I would not be surprised if that is tied to the "critical" configuration on the Certificate that is requiring an intermediate to be in the trust store or something similar.
You can use the above patch for Certbot 1.12.0 to include the first SAN as a Common Name in the subject. Note: I haven't actually tested it with the Buypass (or Let's Encrypt) ACME servers, only Pebble.
This is really puzzling me. I just went through too many old docs.
In this field, "critical" is required by RFC 5280: 4.1.2.6 to be present when the Subject/CN is empty, to identify the SAN extension MUST be included.
I haven't found any old apple developer documents, mailing lists, or tech posts regarding empty CNs on older iOS versions. I feel like there would be a large digital paper trail on that issue if it were a concern.
I can confirm that with the above patch to Certbot, Buypass will gladly issue a cert with a Common Name in the Subject field and will not add a critical to the SAN extension.
Domain names to apply. For multiple domains you can
use multiple -d flags or enter a comma separated list
of domains as a parameter. The first domain provided
will be the subject CN of the certificate, and all
domains will be Subject Alternative Names on the
certificate.
Why isn't the subject CN name already being picked automatically with the official certbot version? Is this worthy of a Github issue in the certbot repo?