Accessing mTLS Websites with Client Certificates on Mac and iPhone

This article documents how to use client certificates to access an internal mTLS website on macOS and iPhone. It covers CanoKey PIV, step-ca, Nginx, and installing system certificates on iOS.

1. Environment and Authentication Flow

The current environment is as follows:

  • CA: The existing CX-Homelab-CA Root CA and CX-Homelab-CA Intermediate CA.
  • Certificate issuance: step-ca.
  • Web server: Nginx 1.25.0.
  • Test site: https://www.home.arpa.
  • Mac client: CanoKey PIV 9A.
  • iPhone client: A client certificate and private key imported through a PKCS#12 file.

The difference between mTLS and ordinary HTTPS is that the server validates the client certificate, while the client must also validate the server certificate. The client certificate must contain the corresponding private key; installing a .crt file alone is generally insufficient to complete client authentication.

The basic flow is as follows:

  1. The client accesses the HTTPS site.
  2. Nginx requests a client certificate.
  3. The browser or operating system selects the client identity and uses the corresponding private key to complete the TLS handshake.
  4. Nginx validates the client certificate’s validity, certificate chain, and intended use.
  5. After validation succeeds, the server allows access to the protected resource.

It is important to note that client certificates and server CA trust are two separate concerns. Installing a client identity does not mean that the device already trusts the private CA that issued the website’s server certificate.

2. Mac: Using CanoKey PIV 9A

2.1 Current Approach

The Mac uses CanoKey’s PIV 9A slot to store the client identity. macOS recognizes the certificate and private key through smart card-related mechanisms, and the browser uses this identity during the TLS handshake.

The following has now been confirmed:

  • The client certificate for CanoKey PIV 9A has been issued.
  • The certificate includes the TLS Web Client Authentication usage.
  • Chrome on macOS has successfully used CanoKey PIV 9A to access the mTLS site.

This proves that the client certificate, private-key signing, and server-side validation chain used during that Chrome session all work correctly.

2.2 Usage

  1. Insert the CanoKey into the Mac.
  2. Confirm that the system recognizes the smart card and its certificates.
  3. Open Chrome.
  4. Visit https://www.home.arpa.
  5. If the browser asks you to select a client certificate, choose the corresponding CanoKey PIV 9A identity.
  6. Enter the PIN or complete the required hardware operation.
  7. Confirm that the page opens normally and check the Nginx logs.

If the certificate selection dialog does not appear, you cannot immediately conclude that the certificate is unavailable. The browser may already have remembered the selection, or the server may not have requested a client certificate during that connection.

2.3 Troubleshooting Commands

View the smart cards recognized by the system:

security list-smartcards

View authentication identities associated with smart cards:

sc_auth identities

View the smart card token status:

sudo security smartcards token -l

If Chrome can access the site but Safari returns:

400 Bad Request
No required SSL certificate was sent

you should separately examine the browser’s client-certificate access behavior, macOS’s recognition of the smart card, and the TLS client-certificate information received by Nginx.

Do not assume that success in one browser means that another browser will necessarily use the same client identity.

3. iPhone: Importing a Client Certificate

3.1 Approach

The iPhone uses a separate client certificate and does not share the private key stored on the CanoKey.

The current approach is as follows:

  1. Generate an iPhone-specific private key on the Mac.
  2. Generate a CSR.
  3. Use the existing step-ca to issue the client certificate.
  4. Package the certificate and private key into an encrypted PKCS#12 file (.p12).
  5. Install the .p12 on the iPhone.
  6. Use an application that supports system client certificates to access the mTLS website.

This approach does not require reinitializing the Root CA or creating a new RSA Intermediate CA.

3.2 Generating the Private Key and CSR on the Mac

Create a dedicated directory:

mkdir -p ~/iphone-mtls
cd ~/iphone-mtls
umask 077

Generate an elliptic-curve private key:

openssl ecparam \
  -genkey \
  -name prime256v1 \
  -noout \
  -out iphone.key

Generate the CSR:

openssl req \
  -new \
  -key iphone.key \
  -subj "/CN=CX iPhone 16 Pro Max" \
  -out iphone.csr

This uses a P-256 (prime256v1) key. Before issuance, confirm that the CA’s certificate template or provisioner has been configured with the correct extended key usage for client certificates.

3.3 Issuing the Certificate with step-ca

step ca sign \
  iphone.csr \
  iphone.crt \
  --not-after=8760h

The validity period parameter requests a certificate valid for approximately one year; the actual validity period remains subject to CA policy.

Inspect the certificate:

openssl x509 \
  -in iphone.crt \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext extendedKeyUsage

Focus on confirming the following:

  • The Subject is the iPhone-specific identity.
  • The Issuer is the expected Homelab Intermediate CA.
  • The validity period is as expected.
  • The Extended Key Usage includes TLS Web Client Authentication.

If the client certificate does not have the clientAuth usage, correct the issuance configuration first rather than importing it directly onto the iPhone.

3.4 Exporting the PKCS#12 File

openssl pkcs12 \
  -export \
  -inkey iphone.key \
  -in iphone.crt \
  -out iphone.p12

When prompted, set an export password for the .p12. This password will usually be required during installation.

If the certificate-chain configuration requires the client to send the Intermediate CA certificate as well, confirm that the exported PKCS#12 contains the appropriate intermediate certificate and check that the final imported identity is complete. Do not package the Root CA private key or Intermediate CA private key into the client file.

3.5 Installing It on the iPhone

  1. Transfer iphone.p12 to the iPhone through a controlled method such as AirDrop.
  2. Open the file on the iPhone.
  3. Follow the system prompts to open Settings and install the downloaded configuration profile or certificate identity.
  4. Enter the PKCS#12 password when prompted.
  5. Under “Settings”, check VPN & Device Management or the relevant profiles page to confirm the installation. The wording may differ slightly between iOS versions.
  6. Confirm that the installed item is an identity containing both the client certificate and private key, rather than merely a public certificate.

If the iPhone does not yet trust the private CA used by the website, the Root CA must be installed separately. For a manually installed root certificate, full trust must also be enabled in accordance with iOS’s certificate trust settings. Installing the client identity and trusting the server CA are two independent steps.

3.6 Accessing the Site with Safari

  1. Confirm that the iPhone is connected to the home network or can access the internal network through a VPN.
  2. Open https://www.home.arpa in Safari.
  3. When the server requests a client certificate, select the appropriate client identity when prompted.
  4. If the page opens normally, check the Nginx logs to confirm that client-certificate validation succeeded.

If the attempt fails, separately troubleshoot DNS, network reachability, server-certificate trust, client-identity installation, and Nginx’s client-certificate validation logs.

4. Why iPhone Chrome Cannot Directly Use System Certificates

Chrome on iOS cannot directly use a client-certificate identity installed through system settings in the same way that Chrome on macOS can.

The official Chromium policy documentation explicitly states that Chrome on Android and iOS can only select client certificates configured by Chrome itself and cannot directly access certificates installed at the operating-system level:

https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/policy/resources/templates/policy_definitions/ContentSettings/AutoSelectCertificateForUrls.yaml

Therefore, importing iphone.p12 into the iPhone system does not mean that Chrome can use it.

Reissuing the certificate, changing the certificate algorithm, or exporting the .p12 again cannot independently resolve this application permission restriction.

For the current approach:

  • iPhone Safari: Prefer the client identity installed in the system.
  • iPhone Chrome: Cannot directly use a system-installed client certificate.
  • Other applications on iOS: Individually confirm whether they implement client-certificate authentication and support the required server address.

5. Certificate and Private-Key Security

A client certificate is not a secret, but its corresponding private key must be protected.

The following points require attention:

  • iphone.key is the private key for the iPhone client identity.
  • iphone.p12 contains both the client certificate and private key and should be treated as a sensitive file.
  • Do not upload .key or .p12 files to public repositories, blog attachments, or untrusted file-sharing services.
  • After the transfer is complete, check the Mac’s temporary directory, Downloads directory, and file-transfer records for any unnecessary copies.
  • If you want to retain the ability to recover, encrypt backups of the private key or PKCS#12 file rather than storing them unprotected for an extended period.
  • If the private key is compromised, revoke the corresponding client certificate or stop trusting it, then regenerate the key and certificate.

To be clear, the iPhone private key in this approach is generated on the Mac and then imported onto the iPhone. It is not equivalent to a hardware-bound, non-exportable private key generated within the iPhone Secure Enclave.

6. Troubleshooting Order

When mTLS access fails, troubleshoot in the following order to avoid attributing every problem to the certificate.

Step 1: Confirm Network and DNS

Confirm that the client can resolve www.home.arpa and connect to Nginx’s HTTPS port.

Step 2: Confirm Server-Certificate Trust

Confirm that the client trusts the CA that issued the website’s server certificate, and that the server certificate’s domain, validity period, and certificate chain are all correct.

Step 3: Confirm the Client Identity

Check the client certificate’s validity period, the clientAuth extended key usage, and whether the client private key is available.

Step 4: Confirm the Nginx Validation Configuration

Check whether the CA file referenced by ssl_client_certificate contains the correct client-certificate issuance chain, and confirm that the ssl_verify_client and ssl_verify_depth settings are appropriate for the current CA hierarchy.

Step 5: Distinguish Between No Certificate Being Sent and Certificate Validation Failure

These two errors are not the same:

  • No required SSL certificate was sent: Usually means that the TLS handshake did not receive the client certificate requested by the server.
  • Client-certificate validation failure: May be related to the certificate chain, validity period, usage, or trust configuration.

Use the Nginx error log and the specific client’s behavior to determine the cause; do not draw conclusions solely from the error page displayed by the browser.

7. Summary of the Current Approach

PlatformClient IdentityCurrent Status
macOS ChromeCanoKey PIV 9ASuccess confirmed
macOS SafariCanoKey PIV 9ABrowser behavior requires separate troubleshooting
iPhone SafariImported PKCS#12 identityUsed as a system certificate identity
iPhone ChromeSystem-installed PKCS#12 identityDirect use of system certificates is not supported

The simplest division at present is to use CanoKey PIV 9A on the Mac and a separate client certificate on the iPhone. When accessing an internal mTLS website, prefer a browser that supports the corresponding client identity.

If client-certificate authentication is to be used for Bitwarden in the future, the Bitwarden app’s own mTLS connection to its server should be designed separately from the browser’s use of mTLS to access ordinary websites.